@@ -8,6 +8,7 @@ | |||
3.1 [将1078的数据(h264)编码成FLV](#1078flv) | |||
3.2 [将1078的数据(h264)编码成HLS](#1078hls) | |||
3.3 [将1078的数据(h264)编码成FMp4](#1078fmp4) | |||
4. ***====音频部分暂未实现====*** | |||
[](https://github.com/SmallChi/JT1078/blob/master/LICENSE)[]() | |||
@@ -18,6 +19,7 @@ | |||
| Install-Package JT1078 |  |  | | |||
| Install-Package JT1078.Flv |  |  | | |||
| Install-Package JT1078.Hls |  |  | | |||
| Install-Package JT1078.FMp4 |  |  | | |||
| Install-Package JT808.Protocol.Extensions.JT1078 |  |  | | |||
| Install-Package JT809.Protocol.Extensions.JT1078 |  |  | | |||
@@ -180,7 +182,13 @@ Platform=AnyCpu Server=False Toolchain=.NET Core 3.1 | |||
3. 掌握TS编码; | |||
4. 掌握Hls编码; | |||
> 音频暂未实现 | |||
## <span id="1078fmp4">基于JT1078的FMp4视频编码器</span> | |||
### 前提条件 | |||
1. 掌握JT078解码; | |||
2. 了解H264解码; | |||
3. 掌握FMp4编码; | |||
### 使用BenchmarkDotNet性能测试报告(只是玩玩,不能当真) | |||
@@ -6,8 +6,16 @@ using System.Text; | |||
namespace JT1078.FMp4 | |||
{ | |||
/// <summary> | |||
/// stco | |||
/// </summary> | |||
public class ChunkOffsetBox : FullBox, IFMp4MessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// stco | |||
/// </summary> | |||
/// <param name="version"></param> | |||
/// <param name="flags"></param> | |||
public ChunkOffsetBox( byte version=0, uint flags=0) : base("stco", version, flags) | |||
{ | |||
} | |||
@@ -20,7 +28,21 @@ namespace JT1078.FMp4 | |||
public void ToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
throw new NotImplementedException(); | |||
Start(ref writer); | |||
WriterFullBoxToBuffer(ref writer); | |||
if(ChunkOffset!=null && ChunkOffset.Count > 0) | |||
{ | |||
writer.WriteUInt32((uint)ChunkOffset.Count); | |||
foreach(var item in ChunkOffset) | |||
{ | |||
writer.WriteUInt32(item); | |||
} | |||
} | |||
else | |||
{ | |||
writer.WriteUInt32(0); | |||
} | |||
End(ref writer); | |||
} | |||
} | |||
} |
@@ -6,8 +6,16 @@ using System.Text; | |||
namespace JT1078.FMp4 | |||
{ | |||
/// <summary> | |||
/// ctts | |||
/// </summary> | |||
public class CompositionOffsetBox : FullBox, IFMp4MessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// ctts | |||
/// </summary> | |||
/// <param name="version"></param> | |||
/// <param name="flags"></param> | |||
public CompositionOffsetBox(byte version=0, uint flags=0) : base("ctts", version, flags) | |||
{ | |||
} | |||
@@ -17,7 +25,30 @@ namespace JT1078.FMp4 | |||
public void ToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
throw new NotImplementedException(); | |||
Start(ref writer); | |||
WriterFullBoxToBuffer(ref writer); | |||
if(CompositionOffsetInfos!=null && CompositionOffsetInfos.Count > 0) | |||
{ | |||
writer.WriteUInt32((uint)CompositionOffsetInfos.Count); | |||
foreach(var item in CompositionOffsetInfos) | |||
{ | |||
if (Version == 0) | |||
{ | |||
writer.WriteUInt32(item.SampleCount); | |||
writer.WriteUInt32(item.SampleOffset); | |||
} | |||
else | |||
{ | |||
writer.WriteUInt32(item.SampleCount); | |||
writer.WriteInt32(item.SignedSampleOffset); | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
writer.WriteUInt32(0); | |||
} | |||
End(ref writer); | |||
} | |||
public class CompositionOffsetInfo | |||
@@ -1,4 +1,6 @@ | |||
using System; | |||
using JT1078.FMp4.Interfaces; | |||
using JT1078.FMp4.MessagePack; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
@@ -7,7 +9,7 @@ namespace JT1078.FMp4 | |||
/// <summary> | |||
/// mdia | |||
/// </summary> | |||
public class MediaBox : Mp4Box | |||
public class MediaBox : Mp4Box, IFMp4MessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// mdia | |||
@@ -27,5 +29,14 @@ namespace JT1078.FMp4 | |||
/// minf | |||
/// </summary> | |||
public MediaInformationBox MediaInformationBox { get; set; } | |||
public void ToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
Start(ref writer); | |||
MediaHeaderBox.ToBuffer(ref writer); | |||
HandlerBox.ToBuffer(ref writer); | |||
MediaInformationBox.ToBuffer(ref writer); | |||
End(ref writer); | |||
} | |||
} | |||
} |
@@ -27,7 +27,7 @@ namespace JT1078.FMp4 | |||
/// </summary> | |||
public TrackBox TrackBox { get; set; } | |||
/// <summary> | |||
/// trak | |||
/// mvex | |||
/// </summary> | |||
public MovieExtendsBox MovieExtendsBox { get; set; } | |||
@@ -35,7 +35,8 @@ namespace JT1078.FMp4 | |||
{ | |||
Start(ref writer); | |||
MovieHeaderBox.ToBuffer(ref writer); | |||
TrackBox.ToBuffer(ref writer); | |||
MovieExtendsBox.ToBuffer(ref writer); | |||
End(ref writer); | |||
} | |||
} | |||
@@ -1,4 +1,6 @@ | |||
using System; | |||
using JT1078.FMp4.Interfaces; | |||
using JT1078.FMp4.MessagePack; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
@@ -7,7 +9,7 @@ namespace JT1078.FMp4 | |||
/// <summary> | |||
/// mvex | |||
/// </summary> | |||
public class MovieExtendsBox : Mp4Box | |||
public class MovieExtendsBox : Mp4Box, IFMp4MessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// mvex | |||
@@ -17,5 +19,22 @@ namespace JT1078.FMp4 | |||
} | |||
public MovieExtendsHeaderBox MovieExtendsHeaderBox { get; set; } | |||
public List<TrackExtendsBox> TrackExtendsBoxs { get; set; } | |||
public void ToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
Start(ref writer); | |||
if (MovieExtendsHeaderBox != null) | |||
{ | |||
MovieExtendsHeaderBox.ToBuffer(ref writer); | |||
} | |||
if (TrackExtendsBoxs != null) | |||
{ | |||
foreach(var item in TrackExtendsBoxs) | |||
{ | |||
item.ToBuffer(ref writer); | |||
} | |||
} | |||
End(ref writer); | |||
} | |||
} | |||
} |
@@ -1,14 +1,33 @@ | |||
using System; | |||
using JT1078.FMp4.Interfaces; | |||
using JT1078.FMp4.MessagePack; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT1078.FMp4 | |||
{ | |||
public class MovieExtendsHeaderBox : FullBox | |||
/// <summary> | |||
/// mehd | |||
/// </summary> | |||
public class MovieExtendsHeaderBox : FullBox, IFMp4MessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// mehd | |||
/// </summary> | |||
/// <param name="version"></param> | |||
/// <param name="flags"></param> | |||
public MovieExtendsHeaderBox( byte version, uint flags=0) : base("mehd", version, flags) | |||
{ | |||
} | |||
public uint FragmentDuration { get; set; } | |||
public void ToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
Start(ref writer); | |||
WriterFullBoxToBuffer(ref writer); | |||
writer.WriteUInt32(FragmentDuration); | |||
End(ref writer); | |||
} | |||
} | |||
} |
@@ -32,7 +32,8 @@ namespace JT1078.FMp4 | |||
WriterFullBoxToBuffer(ref writer); | |||
if(SampleEntries!=null && SampleEntries.Count > 0) | |||
{ | |||
foreach(var item in SampleEntries) | |||
writer.WriteUInt32((uint)SampleEntries.Count); | |||
foreach (var item in SampleEntries) | |||
{ | |||
item.ToBuffer(ref writer); | |||
} | |||
@@ -6,8 +6,16 @@ using System.Text; | |||
namespace JT1078.FMp4 | |||
{ | |||
/// <summary> | |||
/// stsc | |||
/// </summary> | |||
public class SampleToChunkBox : FullBox, IFMp4MessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// stsc | |||
/// </summary> | |||
/// <param name="version"></param> | |||
/// <param name="flags"></param> | |||
public SampleToChunkBox(byte version=0, uint flags=0) : base("stsc", version, flags) | |||
{ | |||
} | |||
@@ -16,7 +24,23 @@ namespace JT1078.FMp4 | |||
public void ToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
throw new NotImplementedException(); | |||
Start(ref writer); | |||
WriterFullBoxToBuffer(ref writer); | |||
if(SampleToChunkInfos!=null && SampleToChunkInfos.Count > 0) | |||
{ | |||
writer.WriteUInt32((uint)SampleToChunkInfos.Count); | |||
foreach(var item in SampleToChunkInfos) | |||
{ | |||
writer.WriteUInt32(item.FirstChunk); | |||
writer.WriteUInt32(item.SamplesPerChunk); | |||
writer.WriteUInt32(item.SampleDescriptionIindex); | |||
} | |||
} | |||
else | |||
{ | |||
writer.WriteUInt32(0); | |||
} | |||
End(ref writer); | |||
} | |||
public class SampleToChunkInfo | |||
@@ -6,8 +6,16 @@ using System.Text; | |||
namespace JT1078.FMp4 | |||
{ | |||
/// <summary> | |||
/// stts | |||
/// </summary> | |||
public class TimeToSampleBox : FullBox, IFMp4MessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// stts | |||
/// </summary> | |||
/// <param name="version"></param> | |||
/// <param name="flags"></param> | |||
public TimeToSampleBox(byte version = 0, uint flags = 0) : base("stts", version, flags) | |||
{ | |||
} | |||
@@ -18,7 +26,22 @@ namespace JT1078.FMp4 | |||
public void ToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
throw new NotImplementedException(); | |||
Start(ref writer); | |||
WriterFullBoxToBuffer(ref writer); | |||
if(TimeToSampleInfos!=null && TimeToSampleInfos.Count > 0) | |||
{ | |||
writer.WriteUInt32((uint)TimeToSampleInfos.Count); | |||
foreach (var item in TimeToSampleInfos) | |||
{ | |||
writer.WriteUInt32(item.SampleCount); | |||
writer.WriteUInt32(item.SampleDelta); | |||
} | |||
} | |||
else | |||
{ | |||
writer.WriteUInt32(0); | |||
} | |||
End(ref writer); | |||
} | |||
public class TimeToSampleInfo | |||
@@ -1,4 +1,6 @@ | |||
using System; | |||
using JT1078.FMp4.Interfaces; | |||
using JT1078.FMp4.MessagePack; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
@@ -7,7 +9,7 @@ namespace JT1078.FMp4 | |||
/// <summary> | |||
/// trak | |||
/// </summary> | |||
public class TrackBox : Mp4Box | |||
public class TrackBox : Mp4Box, IFMp4MessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// trak | |||
@@ -25,5 +27,13 @@ namespace JT1078.FMp4 | |||
/// mdia | |||
/// </summary> | |||
public MediaBox MediaBox { get; set; } | |||
public void ToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
Start(ref writer); | |||
TrackHeaderBox.ToBuffer(ref writer); | |||
MediaBox.ToBuffer(ref writer); | |||
End(ref writer); | |||
} | |||
} | |||
} |
@@ -1,10 +1,12 @@ | |||
using System; | |||
using JT1078.FMp4.Interfaces; | |||
using JT1078.FMp4.MessagePack; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT1078.FMp4 | |||
{ | |||
public class TrackExtendsBox : FullBox | |||
public class TrackExtendsBox : FullBox, IFMp4MessagePackFormatter | |||
{ | |||
public TrackExtendsBox(byte version=0, uint flags=0) : base("trex", version, flags) | |||
{ | |||
@@ -15,5 +17,17 @@ namespace JT1078.FMp4 | |||
public uint DefaultSampleDuration { get; set; } | |||
public uint DefaultSampleSize { get; set; } | |||
public uint DefaultSampleFlags { get; set; } | |||
public void ToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
Start(ref writer); | |||
WriterFullBoxToBuffer(ref writer); | |||
writer.WriteUInt32(TrackID); | |||
writer.WriteUInt32(DefaultSampleDescriptionIndex); | |||
writer.WriteUInt32(DefaultSampleDuration); | |||
writer.WriteUInt32(DefaultSampleSize); | |||
writer.WriteUInt32(DefaultSampleFlags); | |||
End(ref writer); | |||
} | |||
} | |||
} |
@@ -747,7 +747,7 @@ | |||
</summary> | |||
<param name="writer"></param> | |||
</member> | |||
<!-- Badly formed XML comment ignored for member "P:JT1078.FMp4.Samples.AudioSampleEntry.Samplerate" --> | |||
<!-- Badly formed XML comment ignored for member "P:JT1078.FMp4.Samples.AudioSampleEntry.SampleRate" --> | |||
<member name="T:JT1078.FMp4.Samples.AVC1SampleEntry"> | |||
<summary> | |||
avc1 | |||
@@ -1,4 +1,5 @@ | |||
using System; | |||
using JT1078.FMp4.MessagePack; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
@@ -15,8 +16,22 @@ namespace JT1078.FMp4.Samples | |||
public ushort PreDefined { get; set; } = 0; | |||
public ushort Reserved2 { get; set; } = 0; | |||
/// <summary> | |||
/// { default samplerate of media}<<16; | |||
/// | |||
/// default samplerate of media << 16; | |||
/// </summary> | |||
public uint Samplerate{ get; set; } | |||
public uint SampleRate{ get; set; } | |||
protected void WriterAudioSampleEntryToBuffer(ref FMp4MessagePackWriter writer) | |||
{ | |||
foreach(var item in Reserved1) | |||
{ | |||
writer.WriteUInt32(item); | |||
} | |||
writer.WriteUInt16(ChannelCount); | |||
writer.WriteUInt16(SampleSize); | |||
writer.WriteUInt16(PreDefined); | |||
writer.WriteUInt16(Reserved2); | |||
writer.WriteUInt32(SampleRate<<16); | |||
} | |||
} | |||
} |