浏览代码

1.测试fmp4

2.整理添加相应文件
master
SmallChi(Koike) 3 年前
父节点
当前提交
d63476b981
共有 16 个文件被更改,包括 200 次插入17455 次删除
  1. 二进制
      doc/video/JT1078_5.flv
  2. 二进制
      doc/video/jt1078_5.h264
  3. +0
    -0
      doc/video/jt1078_5.txt
  4. +26
    -25
      src/JT1078.FMp4.Test/H264/index.html
  5. +0
    -3
      src/JT1078.FMp4.Test/JT1078.FMp4.Test.csproj
  6. +48
    -70
      src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs
  7. +89
    -110
      src/JT1078.FMp4/FMp4Encoder.cs
  8. +1
    -1
      src/JT1078.FMp4/JT1078.FMp4.csproj
  9. +1
    -24
      src/JT1078.FMp4/JT1078.FMp4.xml
  10. +0
    -17215
      src/JT1078.Hls.Test/H264/1078视频数据.txt
  11. +1
    -4
      src/JT1078.Hls.Test/JT1078.Hls.Test.csproj
  12. +1
    -1
      src/JT1078.Hls.Test/M3U8_Test.cs
  13. +21
    -0
      src/JT1078.Protocol.Test/H264/H264DecoderTest.cs
  14. +3
    -0
      src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj
  15. +3
    -0
      src/JT1078.SignalR.Test/JT1078.SignalR.Test.csproj
  16. +6
    -2
      src/JT1078.SignalR.Test/Services/ToWebSocketService.cs

二进制
doc/video/JT1078_5.flv 查看文件


二进制
doc/video/jt1078_5.h264 查看文件


src/JT1078.FMp4.Test/H264/1078视频数据.txt → doc/video/jt1078_5.txt 查看文件


+ 26
- 25
src/JT1078.FMp4.Test/H264/index.html 查看文件

@@ -19,8 +19,7 @@
//var mimeCodec = 'video/mp4;codecs="avc1.4D0014, mp4a.40.2"';
// *** USER PARAMETERS ***
var verbose = true;
// var verbose = true; // enable for saturating the console ..
var buffering_sec = 1; // use some reasonable value
var buffering_sec = 3; // use some reasonable value
var buffering_sec_seek = buffering_sec * 0.9;
// ..seek the stream if it's this much away or
// from the last available timestamp
@@ -119,45 +118,44 @@
// return;
// }
// keep the latency to minimum
let latest = stream_live.duration;
if ((stream_live.duration >= buffering_sec) &&
((latest - stream_live.currentTime) > buffering_sec_seek)) {
console.log("seek from ", stream_live.currentTime, " to ", latest);
df = (stream_live.duration - stream_live.currentTime); // this much away from the last available frame
if ((df > buffering_sec_seek)) {
seek_to = stream_live.duration - buffering_sec_seek_distance;
stream_live.currentTime = seek_to;
}
}
data = arr;
if (!stream_started) {
// let latest = stream_live.duration;
// if ((stream_live.duration >= buffering_sec) && ((latest - stream_live.currentTime) > buffering_sec_seek)) {
// console.log("seek from ", stream_live.currentTime, " to ", latest);
// df = (stream_live.duration - stream_live.currentTime); // this much away from the last available frame
// if ((df > buffering_sec_seek)) {
// seek_to = stream_live.duration - buffering_sec_seek_distance;
// stream_live.currentTime = seek_to;
// }
// }
if (!source_buffer.updating) {
if (verbose) { console.log("Streaming started: ", memview[0], memview[1], memview[2], memview[3], memview[4]); }
stream_started = true;
source_buffer.appendBuffer(data);
source_buffer.appendBuffer(arr);
cc = cc + 1;
return;
}else{
queue.push(arr); // add to the end
}
queue.push(data); // add to the end
if (verbose) { console.log("queue push:", queue.length); }
}

function loadPacket() { // called when source_buffer is ready for more
if (!source_buffer.updating) { // really, really ready
if (queue.length > 0) {
inp = queue.shift(); // pop from the beginning
var inp = queue.shift(); // pop from the beginning
if (verbose) { console.log("queue pop:", queue.length); }
var memview = new Uint8Array(inp);
if (verbose) { console.log(" ==> writing buffer with", memview[0], memview[1], memview[2], memview[3]); }
source_buffer.appendBuffer(inp);
cc = cc + 1;
}
else { // the queue runs empty, so the next packet is fed directly
stream_started = false;
}
}
else { // so it was not?
// else { // the queue runs empty, so the next packet is fed directly
// stream_started = false;
// }
}
// else {
// // so it was not?

// }
}

function opened() { // MediaSource object is ready to go
@@ -175,7 +173,10 @@
ws.on("video", (message) => {
var buff=base64ToArrayBuffer(message);
//console.log(buff);
putPacket(buff);
//putPacket(buff);
//先直接喂进去
//mvhd.duration 谷歌浏览器不会缓存
source_buffer.appendBuffer(buff);
});
ws.start().catch(err => console.error(err));
}


+ 0
- 3
src/JT1078.FMp4.Test/JT1078.FMp4.Test.csproj 查看文件

@@ -40,9 +40,6 @@
<None Update="FMP4\fragmented_demo_trun.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="H264\1078视频数据.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="H264\index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>


+ 48
- 70
src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs 查看文件

@@ -24,7 +24,7 @@ namespace JT1078.FMp4.Test
var jT1078Package = ParseNALUTest();
H264Decoder decoder = new H264Decoder();
var nalus = decoder.ParseNALU(jT1078Package);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS);
//SPS
spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS);
@@ -434,67 +434,68 @@ namespace JT1078.FMp4.Test
}

[Fact]
public void Test3_1()
public void Test4()
{
FMp4EncoderInfo encoderInfo = new FMp4EncoderInfo();
FMp4Encoder fMp4Encoder = new FMp4Encoder();
var packages = ParseNALUTests1();
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.mp4");
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);
//fragment moof n
Dictionary<string, JT1078Package> memoryCache = new Dictionary<string, JT1078Package>();
bool flag = true;
var ftyp = fMp4Encoder.EncoderFtypBox();
fileStream.Write(ftyp);

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)
{
string key = $"{package.GetKey()}_{0}";
if (package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧)
List<H264NALU> h264NALUs = h264Decoder.ParseNALU(package);
foreach (var nalu in h264NALUs)
{
if (memoryCache.TryGetValue(key, out var pack))
if (nalu.Slice)
{
memoryCache[key] = package;
}
else {
memoryCache.Add(key, package);
//H264 NALU slice first_mb_in_slice
nalus.Add(nalu);
}
}
if (flag)
{
if (memoryCache.TryGetValue(key, out var data))
else
{
var buffer = fMp4Encoder.EncoderVideo(package, encoderInfo, true);
fileStream.Write(buffer);
if (nalus.Count > 0)
{
var otherBuffer = fMp4Encoder.EncoderOtherVideoBox(nalus);
fileStream.Write(otherBuffer);
nalus.Clear();
}
nalus.Add(nalu);
}
flag = false;
}
else {
var buffer = fMp4Encoder.EncoderVideo(package, encoderInfo, false);
fileStream.Write(buffer);
}
}
}
fileStream.Close();
}

[Fact]
public void Test4()
public void Test5()
{
FMp4EncoderInfo encoderInfo = new FMp4EncoderInfo();
FMp4Encoder fMp4Encoder = new FMp4Encoder();
H264Decoder h264Decoder = new H264Decoder();
var packages = ParseNALUTests();
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_5.mp4");
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_6.mp4");
if (File.Exists(filepath))
{
File.Delete(filepath);
}

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]);
@@ -502,36 +503,31 @@ 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>();
foreach (var package in packages)
{
List<H264NALU> h264NALUs = h264Decoder.ParseNALU(package);
foreach (var nalu in h264NALUs)
if (package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧)
{
if (nalu.Slice)
if (nalus.Count > 0)
{
//H264 NALU slice first_mb_in_slice
nalus.Add(nalu);
}
else
{
if (nalus.Count > 0)
{

var otherBuffer = fMp4Encoder.EncoderOtherVideoBox(nalus, encoderInfo);
encoderInfo.SampleSize += (uint)otherBuffer.Length;
fileStream.Write(otherBuffer);
nalus.Clear();
}
nalus.Add(nalu);
var otherBuffer = fMp4Encoder.EncoderOtherVideoBox(nalus);
fileStream.Write(otherBuffer);
nalus.Clear();
}
}
nalus = nalus.Concat(h264NALUs).ToList();
}
if (nalus.Count > 0)
{
var otherBuffer = fMp4Encoder.EncoderOtherVideoBox(nalus);
fileStream.Write(otherBuffer);
nalus.Clear();
}
fileStream.Close();
}
}

[Fact]
public void tkhd_width_height_test()
@@ -588,7 +584,7 @@ namespace JT1078.FMp4.Test
public JT1078Package ParseNALUTest()
{
JT1078Package Package = null;
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_3.txt"));
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_1.txt"));
int mergeBodyLength = 0;
foreach (var line in lines)
{
@@ -600,6 +596,7 @@ namespace JT1078.FMp4.Test
}
return Package;
}

public List<JT1078Package> ParseNALUTests()
{
List<JT1078Package> packages = new List<JT1078Package>();
@@ -619,24 +616,5 @@ 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;
}
}
}

+ 89
- 110
src/JT1078.FMp4/FMp4Encoder.cs 查看文件

@@ -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;
@@ -45,7 +45,7 @@ namespace JT1078.FMp4
/// </summary>
public FMp4Encoder()
{
//TrackInfos = new Dictionary<string, TrackInfo>(StringComparer.OrdinalIgnoreCase);
TrackInfos = new Dictionary<string, TrackInfo>(StringComparer.OrdinalIgnoreCase);
}

/// <summary>
@@ -63,16 +63,11 @@ namespace JT1078.FMp4
fileTypeBox.MajorBrand = "isom";
fileTypeBox.MinorVersion = "\0\0\u0002\0";
fileTypeBox.CompatibleBrands.Add("isom");
fileTypeBox.CompatibleBrands.Add("iso6");
fileTypeBox.CompatibleBrands.Add("iso2");
fileTypeBox.CompatibleBrands.Add("avc1");
fileTypeBox.CompatibleBrands.Add("mp41");
//fileTypeBox.CompatibleBrands.Add("isom");
//fileTypeBox.CompatibleBrands.Add("iso2");
//fileTypeBox.CompatibleBrands.Add("avc1");
//fileTypeBox.CompatibleBrands.Add("mp41");
//fileTypeBox.CompatibleBrands.Add("iso5");
//fileTypeBox.CompatibleBrands.Add("iso6");
fileTypeBox.CompatibleBrands.Add("iso5");
fileTypeBox.CompatibleBrands.Add("iso6");
fileTypeBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
return data;
@@ -97,19 +92,17 @@ namespace JT1078.FMp4
var spsInfo = h264GolombReader.ReadSPS();
//moov
MovieBox movieBox = new MovieBox();
movieBox.MovieHeaderBox = new MovieHeaderBox(0, 0);
movieBox.MovieHeaderBox = new MovieHeaderBox(0, 2);
movieBox.MovieHeaderBox.CreationTime = 0;
movieBox.MovieHeaderBox.ModificationTime = 0;
movieBox.MovieHeaderBox.Duration = 0;
movieBox.MovieHeaderBox.Timescale = 1000;
movieBox.MovieHeaderBox.Rate = 0x00010000;//typically 1.0 媒体速率,这个值代表原始倍速
movieBox.MovieHeaderBox.Volume = 0x0100;// typically,1.0 full volume 媒体音量,这个值代表满音量
movieBox.MovieHeaderBox.NextTrackID = 2;
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 = TrackID;//1
movieBox.TrackBox.TrackHeaderBox.TrackID = TrackID;
movieBox.TrackBox.TrackHeaderBox.Duration = 0;
movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false;
movieBox.TrackBox.TrackHeaderBox.Width = (uint)spsInfo.width;
@@ -144,15 +137,15 @@ namespace JT1078.FMp4
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.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 = TrackID;//1
trex.DefaultSampleDescriptionIndex = SampleDescriptionIndex;//1
trex.TrackID = TrackID;
trex.DefaultSampleDescriptionIndex = SampleDescriptionIndex;
trex.DefaultSampleDuration = 0;
trex.DefaultSampleSize = 0;
trex.DefaultSampleFlags = 0;
@@ -171,113 +164,99 @@ namespace JT1078.FMp4
/// 编码其他视频数据盒子
/// </summary>
/// <returns></returns>
public byte[] EncoderOtherVideoBox(List<H264NALU> nalus, FMp4EncoderInfo encoderInfo)
public byte[] EncoderOtherVideoBox(in List<H264NALU> nalus)
{
byte[] buffer= buffer = FMp4ArrayPool.Rent(nalus.Sum(m=>m.RawData.Length + m.StartCodePrefix.Length) + 4096);
byte[] buffer = FMp4ArrayPool.Rent(nalus.Sum(s => s.RawData.Length + s.StartCodePrefix.Length) + 4096);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
try
{
FragmentBox fragmentBox = new FragmentBox();
fragmentBox.MovieFragmentBox = new MovieFragmentBox();
fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox();
fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = encoderInfo.SequenceNumber;
fragmentBox.MovieFragmentBox.TrackFragmentBox = new TrackFragmentBox();
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(TfhdFlags);//0x39
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = TrackID;//1
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));
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = DefaultSampleFlags;
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = nalus[0].Timestamp * 1000;
var truns = new List<TrackRunBox.TrackRunInfo>();
List<byte[]> rawdatas = new List<byte[]>();
uint iSize = 0;
ulong lastTimestamp = 0;
string key = string.Empty;
for (var i = 0; i < nalus.Count; i++)
{
var nalu = nalus[i];
if (string.IsNullOrEmpty(key))
{
key = nalu.GetKey();
}
rawdatas.Add(nalu.RawData);
if (nalu.DataType == Protocol.Enums.JT1078DataType.视频I帧)
{
iSize += (uint)(nalu.RawData.Length + nalu.StartCodePrefix.Length);
}
else
{
if (iSize > 0)
{
truns.Add(new TrackRunBox.TrackRunInfo()
{
SampleSize = iSize,
});
iSize = 0;
}
truns.Add(new TrackRunBox.TrackRunInfo()
{
SampleSize = (uint)(nalu.RawData.Length + nalu.StartCodePrefix.Length),
});
}
if (i == (nalus.Count - 1))
{
lastTimestamp = nalu.Timestamp;
}
}
if (TrackInfos.TryGetValue(key, out TrackInfo trackInfo))
{
if (trackInfo.SN == uint.MaxValue)
{
trackInfo.SN = 1;
}
trackInfo.SN++;
}
else
{
trackInfo = new TrackInfo { SN = 1, DTS = 0 };
TrackInfos.Add(key, trackInfo);
}
var movieFragmentBox = new MovieFragmentBox();
movieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox();
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = trackInfo.SN;
movieFragmentBox.TrackFragmentBox = new TrackFragmentBox();
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(TfhdFlags);
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = TrackID;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.SampleDescriptionIndex = SampleDescriptionIndex;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = DefaultSampleDuration;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = truns[0].SampleSize;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = DefaultSampleFlags;
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = trackInfo.DTS;
trackInfo.DTS += (ulong)(truns.Count * DefaultSampleDuration);
TrackInfos[key] = trackInfo;
//trun
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);
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: TrunFlags);
movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = FirstSampleFlags;
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = truns;
movieFragmentBox.ToBuffer(ref writer);

var mediaDataBox = new MediaDataBox();
mediaDataBox.Data = rawdatas;
mediaDataBox.ToBuffer(ref writer);

var data = writer.FlushAndGetArray();
return data;
}
finally
{
FMp4ArrayPool.Return(buffer);
}
}
/// <summary>
/// 编码mp4 视频
/// </summary>
/// <param name="package"></param>
/// <param name="needVideoHeader"></param>
/// <returns></returns>
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);
var nalus = h264Decoder.ParseNALU(package);
if (nalus != null && nalus.Count > 0)
{
try
{
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(sei);
nalus.Remove(sps);
nalus.Remove(pps);
if (needVideoHeader)
{
//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, encoderInfo);
encoderInfo.SampleSize += (uint)otherVideoTag.Length;
flvMessagePackWriter.WriteArray(otherVideoTag);
}
finally
{
FMp4ArrayPool.Return(buffer);
}
}
var data = flvMessagePackWriter.FlushAndGetArray();
return data;
}
//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

struct TrackInfo
{
get
{
return sequenceNum++;
}
public uint SN { get; set; }
public ulong DTS { get; set; }
}
}
}

+ 1
- 1
src/JT1078.FMp4/JT1078.FMp4.csproj 查看文件

@@ -14,7 +14,7 @@
<licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl>
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.0.0-preview2</Version>
<Version>1.0.0-preview3</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>


+ 1
- 24
src/JT1078.FMp4/JT1078.FMp4.xml 查看文件

@@ -1337,35 +1337,12 @@
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderOtherVideoBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU},JT1078.FMp4.FMp4EncoderInfo)">
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderOtherVideoBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU}@)">
<summary>
编码其他视频数据盒子
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderVideo(JT1078.Protocol.JT1078Package,JT1078.FMp4.FMp4EncoderInfo,System.Boolean)">
<summary>
编码mp4 视频
</summary>
<param name="package"></param>
<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)


+ 0
- 17215
src/JT1078.Hls.Test/H264/1078视频数据.txt
文件差异内容过多而无法显示
查看文件


+ 1
- 4
src/JT1078.Hls.Test/JT1078.Hls.Test.csproj 查看文件

@@ -42,10 +42,7 @@
<None Include="..\..\doc\video\jt1078_2.txt" Link="H264\jt1078_2.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<None Update="H264\1078视频数据.txt">
<None Include="..\..\doc\video\jt1078_5.txt" Link="H264\jt1078_5.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>


+ 1
- 1
src/JT1078.Hls.Test/M3U8_Test.cs 查看文件

@@ -20,7 +20,7 @@ namespace JT1078.Hls.Test
{
try
{
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "1078视频数据.txt"));
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_5.txt"));
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect("127.0.0.1",1078);
long lasttime = 0;


+ 21
- 0
src/JT1078.Protocol.Test/H264/H264DecoderTest.cs 查看文件

@@ -95,5 +95,26 @@ namespace JT1078.Protocol.Test.H264
}
fileStream.Close();
}

[Fact]
public void ParseNALUTest4()
{
string file = "jt1078_5";
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", $"{file}.txt"));
string filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", $"{file}.h264");
if (File.Exists(filepath))
{
File.Delete(filepath);
}
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[1].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
fileStream.Write(package.Bodies);
}
fileStream.Close();
}
}
}

+ 3
- 0
src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj 查看文件

@@ -29,5 +29,8 @@
<None Include="..\..\doc\video\jt1078_2.txt" Link="H264\jt1078_2.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_5.txt" Link="H264\jt1078_5.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

+ 3
- 0
src/JT1078.SignalR.Test/JT1078.SignalR.Test.csproj 查看文件

@@ -20,5 +20,8 @@
<None Include="..\..\doc\video\jt1078_1_fragmented.mp4" Link="H264\jt1078_1_fragmented.mp4">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_5.txt" Link="H264\jt1078_5.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

+ 6
- 2
src/JT1078.SignalR.Test/Services/ToWebSocketService.cs 查看文件

@@ -52,12 +52,16 @@ namespace JT1078.SignalR.Test.Services
public void a()
{
List<JT1078Package> packages = new List<JT1078Package>();
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_3.txt"));
//var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_3.txt"));
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_5.txt"));
int mergeBodyLength = 0;
foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[6].ToHexBytes();
//jt1078_5
var bytes = data[1].ToHexBytes();
//jt1078_3
//var bytes = data[6].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
mergeBodyLength += package.DataBodyLength;
var packageMerge = JT1078Serializer.Merge(package);


正在加载...
取消
保存