Browse Source

优化mp4协议封装

master
waterliu99 3 years ago
parent
commit
02cef80131
6 changed files with 17327 additions and 33 deletions
  1. +17215
    -0
      src/JT1078.FMp4.Test/H264/1078视频数据.txt
  2. +53
    -6
      src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs
  3. +37
    -22
      src/JT1078.FMp4/FMp4Encoder.cs
  4. +2
    -2
      src/JT1078.FMp4/JT1078.FMp4.csproj
  5. +17
    -2
      src/JT1078.FMp4/JT1078.FMp4.xml
  6. +3
    -1
      src/JT1078.Hls.Test/M3U8_Test.cs

+ 17215
- 0
src/JT1078.FMp4.Test/H264/1078视频数据.txt
File diff suppressed because it is too large
View File


+ 53
- 6
src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs View File

@@ -436,21 +436,45 @@ namespace JT1078.FMp4.Test
[Fact]
public void Test3_1()
{
FMp4EncoderInfo encoderInfo = new FMp4EncoderInfo();
FMp4Encoder fMp4Encoder = new FMp4Encoder();
var packages = ParseNALUTests();
var packages = ParseNALUTests1();
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.mp4");
if (File.Exists(filepath))
{
File.Delete(filepath);
}
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
//fragment moof n
Dictionary<string, JT1078Package> memoryCache = new Dictionary<string, JT1078Package>();
bool flag = true;

foreach (var package in packages)
{
var buffer= fMp4Encoder.EncoderVideo(package, flag);
flag = false;
fileStream.Write(buffer);
string key = $"{package.GetKey()}_{0}";
if (package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧)
{
if (memoryCache.TryGetValue(key, out var pack))
{
memoryCache[key] = package;
}
else {
memoryCache.Add(key, package);
}
}
if (flag)
{
if (memoryCache.TryGetValue(key, out var data))
{
var buffer = fMp4Encoder.EncoderVideo(package, encoderInfo, true);
fileStream.Write(buffer);
}
flag = false;
}
else {
var buffer = fMp4Encoder.EncoderVideo(package, encoderInfo, false);
fileStream.Write(buffer);
}
}
fileStream.Close();
}
@@ -458,6 +482,7 @@ namespace JT1078.FMp4.Test
[Fact]
public void Test4()
{
FMp4EncoderInfo encoderInfo = new FMp4EncoderInfo();
FMp4Encoder fMp4Encoder = new FMp4Encoder();
H264Decoder h264Decoder = new H264Decoder();
var packages = ParseNALUTests();
@@ -469,6 +494,7 @@ namespace JT1078.FMp4.Test

using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
var ftyp = fMp4Encoder.EncoderFtypBox();
encoderInfo.SampleSize += (uint)ftyp.Length;
fileStream.Write(ftyp);

var iNalus = h264Decoder.ParseNALU(packages[0]);
@@ -476,6 +502,7 @@ namespace JT1078.FMp4.Test
var moov = fMp4Encoder.EncoderMoovBox(
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS),
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS));
encoderInfo.SampleSize += (uint)moov.Length;
fileStream.Write(moov);

List<H264NALU> nalus = new List<H264NALU>();
@@ -494,7 +521,8 @@ namespace JT1078.FMp4.Test
if (nalus.Count > 0)
{

var otherBuffer = fMp4Encoder.EncoderOtherVideoBox(nalus);
var otherBuffer = fMp4Encoder.EncoderOtherVideoBox(nalus, encoderInfo);
encoderInfo.SampleSize += (uint)otherBuffer.Length;
fileStream.Write(otherBuffer);
nalus.Clear();
}
@@ -591,5 +619,24 @@ namespace JT1078.FMp4.Test
}
return packages;
}
public List<JT1078Package> ParseNALUTests1()
{
List<JT1078Package> packages = new List<JT1078Package>();
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "1078视频数据.txt"));
int mergeBodyLength = 0;
foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[1].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
mergeBodyLength += package.DataBodyLength;
var packageMerge = JT1078Serializer.Merge(package);
if (packageMerge != null)
{
packages.Add(packageMerge);
}
}
return packages;
}
}
}

+ 37
- 22
src/JT1078.FMp4/FMp4Encoder.cs View File

@@ -30,7 +30,7 @@ namespace JT1078.FMp4
/// </summary>
public class FMp4Encoder
{
Dictionary<string, TrackInfo> TrackInfos;
//Dictionary<string, TrackInfo> TrackInfos;

const uint DefaultSampleDuration = 48000u;
const uint DefaultSampleFlags = 0x1010000;
@@ -39,16 +39,13 @@ namespace JT1078.FMp4
const uint TrunFlags = 0x205;
const uint SampleDescriptionIndex = 1;
const uint TrackID = 1;
//to-do:如何处理多个用户观看,多个设备播放
ulong samplesize = 0;
uint SequenceNumber = 0;

/// <summary>
///
/// </summary>
public FMp4Encoder()
{
TrackInfos = new Dictionary<string, TrackInfo>(StringComparer.OrdinalIgnoreCase);
//TrackInfos = new Dictionary<string, TrackInfo>(StringComparer.OrdinalIgnoreCase);
}

/// <summary>
@@ -78,7 +75,6 @@ namespace JT1078.FMp4
//fileTypeBox.CompatibleBrands.Add("iso6");
fileTypeBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
samplesize += (ulong)data.Length;
return data;
}
finally
@@ -163,7 +159,6 @@ namespace JT1078.FMp4
movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex);
movieBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
samplesize += (ulong)data.Length;
return data;
}
finally
@@ -176,7 +171,7 @@ namespace JT1078.FMp4
/// 编码其他视频数据盒子
/// </summary>
/// <returns></returns>
public byte[] EncoderOtherVideoBox(List<H264NALU> nalus)
public byte[] EncoderOtherVideoBox(List<H264NALU> nalus, FMp4EncoderInfo encoderInfo)
{
byte[] buffer= buffer = FMp4ArrayPool.Rent(nalus.Sum(m=>m.RawData.Length + m.StartCodePrefix.Length) + 4096);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
@@ -185,11 +180,11 @@ namespace JT1078.FMp4
FragmentBox fragmentBox = new FragmentBox();
fragmentBox.MovieFragmentBox = new MovieFragmentBox();
fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox();
fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = SequenceNumber;
fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = encoderInfo.SequenceNumber;
fragmentBox.MovieFragmentBox.TrackFragmentBox = new TrackFragmentBox();
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x39);//TfhdFlags
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(TfhdFlags);//0x39
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = TrackID;//1
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.BaseDataOffset = samplesize;//基于前面盒子的长度
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.BaseDataOffset = encoderInfo.SampleSize;//基于前面盒子的长度
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.SampleDescriptionIndex = SampleDescriptionIndex;
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = DefaultSampleDuration;
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)(nalus.Sum(m => m.RawData.Length + m.StartCodePrefix.Length));
@@ -197,16 +192,14 @@ namespace JT1078.FMp4
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = nalus[0].Timestamp * 1000;
//trun
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x5 );//TrunFlags
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 0;// FirstSampleFlags;
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x5);//TrunFlags
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = FirstSampleFlags;// 0;
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List<TrackRunBox.TrackRunInfo>();
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo());
fragmentBox.MediaDataBox = new MediaDataBox();
fragmentBox.MediaDataBox.Data = nalus.Select(s => s.RawData).ToList();
fragmentBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
samplesize += (ulong)data.Length;
SequenceNumber++;
return data;
}
finally
@@ -220,7 +213,7 @@ namespace JT1078.FMp4
/// <param name="package"></param>
/// <param name="needVideoHeader"></param>
/// <returns></returns>
public byte[] EncoderVideo(JT1078Package package, bool needVideoHeader = false) {
public byte[] EncoderVideo(JT1078Package package, FMp4EncoderInfo encoderInfo, bool needVideoHeader = false) {
H264Decoder h264Decoder = new H264Decoder();
byte[] buffer = FMp4ArrayPool.Rent(package.Bodies.Length * 2 + 4096);
FMp4MessagePackWriter flvMessagePackWriter = new FMp4MessagePackWriter(buffer);
@@ -240,14 +233,16 @@ namespace JT1078.FMp4
//mp4 header
//ftype
var ftypHeader = EncoderFtypBox();
encoderInfo.SampleSize += (uint)ftypHeader.Length;
flvMessagePackWriter.WriteArray(ftypHeader);
// moov
var moov = EncoderMoovBox(sps, pps);
encoderInfo.SampleSize += (uint)moov.Length;
flvMessagePackWriter.WriteArray(moov);
//解析sps
}
var otherVideoTag = EncoderOtherVideoBox(nalus);
var otherVideoTag = EncoderOtherVideoBox(nalus, encoderInfo);
encoderInfo.SampleSize += (uint)otherVideoTag.Length;
flvMessagePackWriter.WriteArray(otherVideoTag);
}
finally
@@ -258,11 +253,31 @@ namespace JT1078.FMp4
var data = flvMessagePackWriter.FlushAndGetArray();
return data;
}

struct TrackInfo
//struct TrackInfo
//{
// public uint SN { get; set; }
// public ulong DTS { get; set; }
//}
}
/// <summary>
/// 编码信息
/// </summary>
public class FMp4EncoderInfo
{
/// <summary>
/// 样本大小,即盒子大小
/// </summary>
public uint SampleSize { get; set; } = 0;
private uint sequenceNum = 0;
/// <summary>
/// 轨道序号
/// </summary>
public uint SequenceNumber
{
public uint SN { get; set; }
public ulong DTS { get; set; }
get
{
return sequenceNum++;
}
}
}
}

+ 2
- 2
src/JT1078.FMp4/JT1078.FMp4.csproj View File

@@ -14,9 +14,9 @@
<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.1</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<DocumentationFile>JT1078.FMp4.xml</DocumentationFile>
</PropertyGroup>


+ 17
- 2
src/JT1078.FMp4/JT1078.FMp4.xml View File

@@ -1337,13 +1337,13 @@
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderOtherVideoBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU})">
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderOtherVideoBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU},JT1078.FMp4.FMp4EncoderInfo)">
<summary>
编码其他视频数据盒子
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderVideo(JT1078.Protocol.JT1078Package,System.Boolean)">
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderVideo(JT1078.Protocol.JT1078Package,JT1078.FMp4.FMp4EncoderInfo,System.Boolean)">
<summary>
编码mp4 视频
</summary>
@@ -1351,6 +1351,21 @@
<param name="needVideoHeader"></param>
<returns></returns>
</member>
<member name="T:JT1078.FMp4.FMp4EncoderInfo">
<summary>
编码信息
</summary>
</member>
<member name="P:JT1078.FMp4.FMp4EncoderInfo.SampleSize">
<summary>
样本大小,即盒子大小
</summary>
</member>
<member name="P:JT1078.FMp4.FMp4EncoderInfo.SequenceNumber">
<summary>
轨道序号
</summary>
</member>
<member name="P:JT1078.FMp4.FullBox.Version">
<summary>
unsigned int(8)


+ 3
- 1
src/JT1078.Hls.Test/M3U8_Test.cs View File

@@ -32,7 +32,9 @@ namespace JT1078.Hls.Test
lasttime = long.Parse(temp[0]);
}
else {
Thread.Sleep(TimeSpan.FromSeconds(long.Parse(temp[0]) - lasttime));
var ts = long.Parse(temp[0]) - lasttime;
if (ts > 3) ts = 3;
Thread.Sleep(TimeSpan.FromSeconds(ts));
lasttime = long.Parse(temp[0]);
}
var data= temp[1].ToHexBytes();


Loading…
Cancel
Save