Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

643 lignes
37 KiB

  1. using JT1078.FMp4.Enums;
  2. using JT1078.FMp4.MessagePack;
  3. using JT1078.FMp4.Samples;
  4. using JT1078.Protocol;
  5. using JT1078.Protocol.Extensions;
  6. using JT1078.Protocol.H264;
  7. using JT1078.Protocol.MessagePack;
  8. using System;
  9. using System.Buffers.Binary;
  10. using System.Collections.Generic;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Threading.Tasks;
  15. using Xunit;
  16. namespace JT1078.FMp4.Test
  17. {
  18. public class JT1078ToFMp4Box_Test
  19. {
  20. [Fact]
  21. public void Test1()
  22. {
  23. var jT1078Package = ParseNALUTest();
  24. H264Decoder decoder = new H264Decoder();
  25. var nalus = decoder.ParseNALU(jT1078Package);
  26. var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS);
  27. //SPS
  28. spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
  29. var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS);
  30. ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData);
  31. //ftyp
  32. FileTypeBox fileTypeBox = new FileTypeBox();
  33. fileTypeBox.MajorBrand = "isom";
  34. fileTypeBox.MinorVersion = "\0\0\u0002\0";
  35. fileTypeBox.CompatibleBrands.Add("isom");
  36. fileTypeBox.CompatibleBrands.Add("iso6");
  37. fileTypeBox.CompatibleBrands.Add("iso2");
  38. fileTypeBox.CompatibleBrands.Add("avc1");
  39. fileTypeBox.CompatibleBrands.Add("mp41");
  40. //moov
  41. MovieBox movieBox = new MovieBox();
  42. movieBox.MovieHeaderBox = new MovieHeaderBox(0, 0);
  43. movieBox.MovieHeaderBox.CreationTime = 0;
  44. movieBox.MovieHeaderBox.ModificationTime = 0;
  45. movieBox.MovieHeaderBox.Duration = 0;
  46. movieBox.MovieHeaderBox.Timescale = 1000;
  47. movieBox.MovieHeaderBox.NextTrackID = 2;
  48. movieBox.TrackBox = new TrackBox();
  49. movieBox.TrackBox.TrackHeaderBox = new TrackHeaderBox(0, 3);
  50. movieBox.TrackBox.TrackHeaderBox.CreationTime = 0;
  51. movieBox.TrackBox.TrackHeaderBox.ModificationTime = 0;
  52. movieBox.TrackBox.TrackHeaderBox.TrackID = 1;
  53. movieBox.TrackBox.TrackHeaderBox.Duration = 0;
  54. movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false;
  55. movieBox.TrackBox.TrackHeaderBox.Width = 352;
  56. movieBox.TrackBox.TrackHeaderBox.Height = 288;
  57. movieBox.TrackBox.MediaBox = new MediaBox();
  58. movieBox.TrackBox.MediaBox.MediaHeaderBox = new MediaHeaderBox();
  59. movieBox.TrackBox.MediaBox.MediaHeaderBox.CreationTime = 0;
  60. movieBox.TrackBox.MediaBox.MediaHeaderBox.ModificationTime = 0;
  61. movieBox.TrackBox.MediaBox.MediaHeaderBox.Timescale = 1200000;
  62. movieBox.TrackBox.MediaBox.MediaHeaderBox.Duration = 0;
  63. movieBox.TrackBox.MediaBox.HandlerBox = new HandlerBox();
  64. movieBox.TrackBox.MediaBox.HandlerBox.HandlerType = HandlerType.vide;
  65. movieBox.TrackBox.MediaBox.HandlerBox.Name = "VideoHandler";
  66. movieBox.TrackBox.MediaBox.MediaInformationBox = new MediaInformationBox();
  67. movieBox.TrackBox.MediaBox.MediaInformationBox.VideoMediaHeaderBox = new VideoMediaHeaderBox();
  68. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox = new DataInformationBox();
  69. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox = new DataReferenceBox();
  70. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List<DataEntryBox>();
  71. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1));
  72. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox();
  73. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox();
  74. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List<SampleEntry>();
  75. AVC1SampleEntry avc1 = new AVC1SampleEntry();
  76. avc1.AVCConfigurationBox = new AVCConfigurationBox();
  77. //h264
  78. avc1.Width = (ushort)movieBox.TrackBox.TrackHeaderBox.Width;
  79. avc1.Height = (ushort)movieBox.TrackBox.TrackHeaderBox.Height;
  80. //MSE codecs avc1.4D0014
  81. //4D 00 14
  82. //AVCProfileIndication profile_compability AVCLevelIndication
  83. avc1.AVCConfigurationBox.AVCLevelIndication = 20;
  84. avc1.AVCConfigurationBox.AVCProfileIndication = 77;
  85. avc1.AVCConfigurationBox.PPSs = new List<byte[]>() { ppsNALU.RawData };
  86. avc1.AVCConfigurationBox.SPSs = new List<byte[]>() { spsNALU.RawData };
  87. avc1.AVCConfigurationBox.ProfileCompatibility = 0;
  88. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries.Add(avc1);
  89. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.TimeToSampleBox = new TimeToSampleBox();
  90. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleToChunkBox = new SampleToChunkBox();
  91. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleSizeBox = new SampleSizeBox();
  92. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.ChunkOffsetBox = new ChunkOffsetBox();
  93. movieBox.MovieExtendsBox = new MovieExtendsBox();
  94. movieBox.MovieExtendsBox.TrackExtendsBoxs = new List<TrackExtendsBox>();
  95. TrackExtendsBox trex = new TrackExtendsBox();
  96. trex.TrackID = 1;
  97. trex.DefaultSampleDescriptionIndex = 1;
  98. trex.DefaultSampleDuration = 0;
  99. trex.DefaultSampleSize = 0;
  100. trex.DefaultSampleFlags = 0;
  101. movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex);
  102. //用户自定义可以不用
  103. //movieBox.UserDataBox = new UserDataBox();
  104. //movieBox.UserDataBox.Data = "0000005a6d657461000000000000002168646c7200000000000000006d6469726170706c0000000000000000000000002d696c737400000025a9746f6f0000001d6461746100000001000000004c61766635382e34352e313030".ToHexBytes();
  105. //fragment moof n
  106. List<FragmentBox> moofs = new List<FragmentBox>();
  107. FragmentBox fragmentBox = new FragmentBox();
  108. fragmentBox.MovieFragmentBox = new MovieFragmentBox();
  109. fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox();
  110. fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = 1;
  111. fragmentBox.MovieFragmentBox.TrackFragmentBox = new TrackFragmentBox();
  112. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x39);
  113. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1;
  114. //todo:BaseDataOffset
  115. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.BaseDataOffset = 0x000000000000028b;
  116. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000;
  117. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)jT1078Package.Bodies.Length;
  118. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000;
  119. //fragmentBox.MovieFragmentBox.TrackFragmentBox.SampleDependencyTypeBox = new SampleDependencyTypeBox();
  120. //fragmentBox.MovieFragmentBox.TrackFragmentBox.SampleDependencyTypeBox.SampleDependencyTypes = new List<SampleDependencyTypeBox.SampleDependencyType>();
  121. //todo:fragmentBox.MovieFragmentBox.TrackFragmentBox.SampleDependencyTypeBox.SampleDependencyTypes
  122. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
  123. //todo:BaseMediaDecodeTime
  124. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = 0;
  125. //trun
  126. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x5);
  127. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.DataOffset = 120;
  128. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 0;
  129. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List<TrackRunBox.TrackRunInfo>();
  130. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo());
  131. fragmentBox.MediaDataBox = new MediaDataBox();
  132. fragmentBox.MediaDataBox.Data = nalus
  133. .Select(s => s.RawData)
  134. .ToList();
  135. moofs.Add(fragmentBox);
  136. //mfra
  137. MovieFragmentRandomAccessBox movieFragmentRandomAccessBox = new MovieFragmentRandomAccessBox();
  138. //mfra->tfra
  139. movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox = new TrackFragmentRandomAccessBox(1);
  140. movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox.TrackID = 0x01;
  141. movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfos = new List<TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfo>();
  142. TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfo trackFragmentRandomAccessInfo1 = new TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfo();
  143. trackFragmentRandomAccessInfo1.Time = 0;
  144. //todo:MoofOffset
  145. trackFragmentRandomAccessInfo1.MoofOffset = 0x000000000000028b;
  146. trackFragmentRandomAccessInfo1.TrafNumber = 0x01;
  147. trackFragmentRandomAccessInfo1.TrunNumber = 0x01;
  148. trackFragmentRandomAccessInfo1.SampleNumber = 0x01;
  149. movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfos.Add(trackFragmentRandomAccessInfo1);
  150. //mfra->mfro
  151. movieFragmentRandomAccessBox.MovieFragmentRandomAccessOffsetBox = new MovieFragmentRandomAccessOffsetBox(0);
  152. //todo:MfraSize
  153. movieFragmentRandomAccessBox.MovieFragmentRandomAccessOffsetBox.MfraSize = 0x00000043;
  154. FMp4Box fMp4Box = new FMp4Box();
  155. fMp4Box.FileTypeBox = fileTypeBox;
  156. fMp4Box.MovieBox = movieBox;
  157. fMp4Box.FragmentBoxs = moofs;
  158. fMp4Box.MovieFragmentRandomAccessBox = movieFragmentRandomAccessBox;
  159. FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[65535]);
  160. fMp4Box.ToBuffer(ref writer);
  161. var buffer = writer.FlushAndGetArray();
  162. var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_1.mp4");
  163. if (File.Exists(filepath))
  164. {
  165. File.Delete(filepath);
  166. }
  167. using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
  168. fileStream.Write(buffer);
  169. fileStream.Close();
  170. }
  171. [Fact]
  172. public void Test2()
  173. {
  174. var jT1078Package = ParseNALUTest();
  175. H264Decoder decoder = new H264Decoder();
  176. var nalus = decoder.ParseNALU(jT1078Package);
  177. var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS);
  178. //SPS
  179. spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
  180. var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS);
  181. ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData);
  182. FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[65535]);
  183. //ftyp
  184. FileTypeBox fileTypeBox = new FileTypeBox();
  185. fileTypeBox.MajorBrand = "isom";
  186. fileTypeBox.MinorVersion = "\0\0\u0002\0";
  187. fileTypeBox.CompatibleBrands.Add("isom");
  188. fileTypeBox.CompatibleBrands.Add("iso6");
  189. fileTypeBox.CompatibleBrands.Add("iso2");
  190. fileTypeBox.CompatibleBrands.Add("avc1");
  191. fileTypeBox.CompatibleBrands.Add("mp41");
  192. //moov
  193. MovieBox movieBox = new MovieBox();
  194. movieBox.MovieHeaderBox = new MovieHeaderBox(0, 0);
  195. movieBox.MovieHeaderBox.CreationTime = 0;
  196. movieBox.MovieHeaderBox.ModificationTime = 0;
  197. movieBox.MovieHeaderBox.Duration = 0;
  198. movieBox.MovieHeaderBox.Timescale = 1000;
  199. movieBox.MovieHeaderBox.NextTrackID = 2;
  200. movieBox.TrackBox = new TrackBox();
  201. movieBox.TrackBox.TrackHeaderBox = new TrackHeaderBox(0, 3);
  202. movieBox.TrackBox.TrackHeaderBox.CreationTime = 0;
  203. movieBox.TrackBox.TrackHeaderBox.ModificationTime = 0;
  204. movieBox.TrackBox.TrackHeaderBox.TrackID = 1;
  205. movieBox.TrackBox.TrackHeaderBox.Duration = 0;
  206. movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false;
  207. movieBox.TrackBox.TrackHeaderBox.Width = 352;
  208. movieBox.TrackBox.TrackHeaderBox.Height = 288;
  209. movieBox.TrackBox.MediaBox = new MediaBox();
  210. movieBox.TrackBox.MediaBox.MediaHeaderBox = new MediaHeaderBox();
  211. movieBox.TrackBox.MediaBox.MediaHeaderBox.CreationTime = 0;
  212. movieBox.TrackBox.MediaBox.MediaHeaderBox.ModificationTime = 0;
  213. movieBox.TrackBox.MediaBox.MediaHeaderBox.Timescale = 1200000;
  214. movieBox.TrackBox.MediaBox.MediaHeaderBox.Duration = 0;
  215. movieBox.TrackBox.MediaBox.HandlerBox = new HandlerBox();
  216. movieBox.TrackBox.MediaBox.HandlerBox.HandlerType = HandlerType.vide;
  217. movieBox.TrackBox.MediaBox.HandlerBox.Name = "VideoHandler";
  218. movieBox.TrackBox.MediaBox.MediaInformationBox = new MediaInformationBox();
  219. movieBox.TrackBox.MediaBox.MediaInformationBox.VideoMediaHeaderBox = new VideoMediaHeaderBox();
  220. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox = new DataInformationBox();
  221. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox = new DataReferenceBox();
  222. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List<DataEntryBox>();
  223. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1));
  224. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox();
  225. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox();
  226. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List<SampleEntry>();
  227. AVC1SampleEntry avc1 = new AVC1SampleEntry();
  228. avc1.AVCConfigurationBox = new AVCConfigurationBox();
  229. //h264
  230. avc1.Width = (ushort)movieBox.TrackBox.TrackHeaderBox.Width;
  231. avc1.Height = (ushort)movieBox.TrackBox.TrackHeaderBox.Height;
  232. avc1.AVCConfigurationBox.AVCLevelIndication = 20;
  233. avc1.AVCConfigurationBox.AVCProfileIndication = 77;
  234. avc1.AVCConfigurationBox.PPSs = new List<byte[]>() { ppsNALU.RawData };
  235. avc1.AVCConfigurationBox.SPSs = new List<byte[]>() { spsNALU.RawData };
  236. avc1.AVCConfigurationBox.ProfileCompatibility = 0;
  237. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries.Add(avc1);
  238. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.TimeToSampleBox = new TimeToSampleBox();
  239. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleToChunkBox = new SampleToChunkBox();
  240. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleSizeBox = new SampleSizeBox();
  241. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.ChunkOffsetBox = new ChunkOffsetBox();
  242. movieBox.MovieExtendsBox = new MovieExtendsBox();
  243. movieBox.MovieExtendsBox.TrackExtendsBoxs = new List<TrackExtendsBox>();
  244. TrackExtendsBox trex = new TrackExtendsBox();
  245. trex.TrackID = 1;
  246. trex.DefaultSampleDescriptionIndex = 1;
  247. trex.DefaultSampleDuration = 0;
  248. trex.DefaultSampleSize = 0;
  249. trex.DefaultSampleFlags = 0;
  250. movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex);
  251. fileTypeBox.ToBuffer(ref writer);
  252. movieBox.ToBuffer(ref writer);
  253. //fragment moof n
  254. List<FragmentBox> moofs = new List<FragmentBox>();
  255. ulong moofOffset = (ulong)writer.GetCurrentPosition();
  256. FragmentBox fragmentBox = new FragmentBox();
  257. fragmentBox.MovieFragmentBox = new MovieFragmentBox();
  258. fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox();
  259. fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = 1;
  260. fragmentBox.MovieFragmentBox.TrackFragmentBox = new TrackFragmentBox();
  261. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x39);
  262. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1;
  263. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.BaseDataOffset = moofOffset;
  264. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000;
  265. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)jT1078Package.Bodies.Length;
  266. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000;
  267. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
  268. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = 0;
  269. //trun
  270. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x5);
  271. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 0;
  272. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List<TrackRunBox.TrackRunInfo>();
  273. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo());
  274. fragmentBox.MediaDataBox = new MediaDataBox();
  275. fragmentBox.MediaDataBox.Data = nalus.Select(s => s.RawData).ToList();
  276. moofs.Add(fragmentBox);
  277. foreach (var moof in moofs)
  278. {
  279. moof.ToBuffer(ref writer);
  280. }
  281. //mfra
  282. MovieFragmentRandomAccessBox movieFragmentRandomAccessBox = new MovieFragmentRandomAccessBox();
  283. //mfra->tfra
  284. movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox = new TrackFragmentRandomAccessBox(1);
  285. movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox.TrackID = 0x01;
  286. movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfos = new List<TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfo>();
  287. TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfo trackFragmentRandomAccessInfo1 = new TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfo();
  288. trackFragmentRandomAccessInfo1.Time = 0;
  289. trackFragmentRandomAccessInfo1.MoofOffset = moofOffset;
  290. trackFragmentRandomAccessInfo1.TrafNumber = 0x01;
  291. trackFragmentRandomAccessInfo1.TrunNumber = 0x01;
  292. trackFragmentRandomAccessInfo1.SampleNumber = 0x01;
  293. movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfos.Add(trackFragmentRandomAccessInfo1);
  294. //mfra->mfro
  295. movieFragmentRandomAccessBox.MovieFragmentRandomAccessOffsetBox = new MovieFragmentRandomAccessOffsetBox(0);
  296. movieFragmentRandomAccessBox.ToBuffer(ref writer);
  297. var buffer = writer.FlushAndGetArray();
  298. var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_2.mp4");
  299. if (File.Exists(filepath))
  300. {
  301. File.Delete(filepath);
  302. }
  303. using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
  304. fileStream.Write(buffer);
  305. fileStream.Close();
  306. }
  307. [Fact]
  308. public void Test3()
  309. {
  310. H264Decoder decoder = new H264Decoder();
  311. var packages = ParseNALUTests();
  312. //10M
  313. FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[10 * 1024 * 1024]);
  314. var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.mp4");
  315. if (File.Exists(filepath))
  316. {
  317. File.Delete(filepath);
  318. }
  319. using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
  320. var jT1078Package = packages.FirstOrDefault();
  321. var nalus = decoder.ParseNALU(jT1078Package);
  322. var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS);
  323. //SPS
  324. spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
  325. var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS);
  326. ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData);
  327. ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData);
  328. var spsInfo = h264GolombReader.ReadSPS();
  329. //ftyp
  330. FileTypeBox fileTypeBox = new FileTypeBox();
  331. fileTypeBox.MajorBrand = "isom";
  332. fileTypeBox.MinorVersion = "\0\0\u0002\0";
  333. fileTypeBox.CompatibleBrands.Add("isom");
  334. fileTypeBox.CompatibleBrands.Add("iso6");
  335. fileTypeBox.CompatibleBrands.Add("iso2");
  336. fileTypeBox.CompatibleBrands.Add("avc1");
  337. fileTypeBox.CompatibleBrands.Add("mp41");
  338. //moov
  339. MovieBox movieBox = new MovieBox();
  340. movieBox.MovieHeaderBox = new MovieHeaderBox(0, 0);
  341. movieBox.MovieHeaderBox.CreationTime = 0;
  342. movieBox.MovieHeaderBox.ModificationTime = 0;
  343. movieBox.MovieHeaderBox.Duration = 0;
  344. movieBox.MovieHeaderBox.Timescale = 1000;
  345. movieBox.MovieHeaderBox.NextTrackID = 2;
  346. movieBox.TrackBox = new TrackBox();
  347. movieBox.TrackBox.TrackHeaderBox = new TrackHeaderBox(0, 3);
  348. movieBox.TrackBox.TrackHeaderBox.CreationTime = 0;
  349. movieBox.TrackBox.TrackHeaderBox.ModificationTime = 0;
  350. movieBox.TrackBox.TrackHeaderBox.TrackID = 1;
  351. movieBox.TrackBox.TrackHeaderBox.Duration = 0;
  352. movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false;
  353. movieBox.TrackBox.TrackHeaderBox.Width = (uint)spsInfo.width;
  354. movieBox.TrackBox.TrackHeaderBox.Height = (uint)spsInfo.height;
  355. movieBox.TrackBox.MediaBox = new MediaBox();
  356. movieBox.TrackBox.MediaBox.MediaHeaderBox = new MediaHeaderBox();
  357. movieBox.TrackBox.MediaBox.MediaHeaderBox.CreationTime = 0;
  358. movieBox.TrackBox.MediaBox.MediaHeaderBox.ModificationTime = 0;
  359. movieBox.TrackBox.MediaBox.MediaHeaderBox.Timescale = 1200000;
  360. movieBox.TrackBox.MediaBox.MediaHeaderBox.Duration = 0;
  361. movieBox.TrackBox.MediaBox.HandlerBox = new HandlerBox();
  362. movieBox.TrackBox.MediaBox.HandlerBox.HandlerType = HandlerType.vide;
  363. movieBox.TrackBox.MediaBox.HandlerBox.Name = "VideoHandler";
  364. movieBox.TrackBox.MediaBox.MediaInformationBox = new MediaInformationBox();
  365. movieBox.TrackBox.MediaBox.MediaInformationBox.VideoMediaHeaderBox = new VideoMediaHeaderBox();
  366. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox = new DataInformationBox();
  367. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox = new DataReferenceBox();
  368. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List<DataEntryBox>();
  369. movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1));
  370. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox();
  371. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox();
  372. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List<SampleEntry>();
  373. AVC1SampleEntry avc1 = new AVC1SampleEntry();
  374. avc1.AVCConfigurationBox = new AVCConfigurationBox();
  375. //h264
  376. avc1.Width = (ushort)movieBox.TrackBox.TrackHeaderBox.Width;
  377. avc1.Height = (ushort)movieBox.TrackBox.TrackHeaderBox.Height;
  378. avc1.AVCConfigurationBox.AVCLevelIndication = spsInfo.levelIdc;
  379. avc1.AVCConfigurationBox.AVCProfileIndication = spsInfo.profileIdc;
  380. avc1.AVCConfigurationBox.ProfileCompatibility = (byte)spsInfo.profileCompat;
  381. avc1.AVCConfigurationBox.PPSs = new List<byte[]>() { ppsNALU.RawData };
  382. avc1.AVCConfigurationBox.SPSs = new List<byte[]>() { spsNALU.RawData };
  383. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries.Add(avc1);
  384. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.TimeToSampleBox = new TimeToSampleBox();
  385. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleToChunkBox = new SampleToChunkBox();
  386. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleSizeBox = new SampleSizeBox();
  387. movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.ChunkOffsetBox = new ChunkOffsetBox();
  388. movieBox.MovieExtendsBox = new MovieExtendsBox();
  389. movieBox.MovieExtendsBox.TrackExtendsBoxs = new List<TrackExtendsBox>();
  390. TrackExtendsBox trex = new TrackExtendsBox();
  391. trex.TrackID = 1;
  392. trex.DefaultSampleDescriptionIndex = 1;
  393. trex.DefaultSampleDuration = 0;
  394. trex.DefaultSampleSize = 0;
  395. trex.DefaultSampleFlags = 0;
  396. movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex);
  397. fileTypeBox.ToBuffer(ref writer);
  398. movieBox.ToBuffer(ref writer);
  399. //fragment moof n
  400. foreach (var package in packages)
  401. {
  402. ulong moofOffset = (ulong)writer.GetCurrentPosition();
  403. var package_nalus = decoder.ParseNALU(package);
  404. FragmentBox fragmentBox = new FragmentBox();
  405. fragmentBox.MovieFragmentBox = new MovieFragmentBox();
  406. fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox();
  407. fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = package.SN;
  408. fragmentBox.MovieFragmentBox.TrackFragmentBox = new TrackFragmentBox();
  409. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x39);
  410. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1;
  411. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.BaseDataOffset = moofOffset;
  412. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000;
  413. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)package.Bodies.Length;
  414. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000;
  415. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
  416. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = package.Timestamp * 1000;
  417. //trun
  418. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x5);
  419. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 0;
  420. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List<TrackRunBox.TrackRunInfo>();
  421. fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo());
  422. fragmentBox.MediaDataBox = new MediaDataBox();
  423. fragmentBox.MediaDataBox.Data = package_nalus.Select(s => s.RawData).ToList();
  424. fragmentBox.ToBuffer(ref writer);
  425. }
  426. var buffer = writer.FlushAndGetArray();
  427. fileStream.Write(buffer);
  428. fileStream.Close();
  429. }
  430. [Fact]
  431. public void Test3_1()
  432. {
  433. FMp4EncoderInfo encoderInfo = new FMp4EncoderInfo();
  434. FMp4Encoder fMp4Encoder = new FMp4Encoder();
  435. var packages = ParseNALUTests1();
  436. var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.mp4");
  437. if (File.Exists(filepath))
  438. {
  439. File.Delete(filepath);
  440. }
  441. using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
  442. //fragment moof n
  443. Dictionary<string, JT1078Package> memoryCache = new Dictionary<string, JT1078Package>();
  444. bool flag = true;
  445. foreach (var package in packages)
  446. {
  447. string key = $"{package.GetKey()}_{0}";
  448. if (package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧)
  449. {
  450. if (memoryCache.TryGetValue(key, out var pack))
  451. {
  452. memoryCache[key] = package;
  453. }
  454. else {
  455. memoryCache.Add(key, package);
  456. }
  457. }
  458. if (flag)
  459. {
  460. if (memoryCache.TryGetValue(key, out var data))
  461. {
  462. var buffer = fMp4Encoder.EncoderVideo(package, encoderInfo, true);
  463. fileStream.Write(buffer);
  464. }
  465. flag = false;
  466. }
  467. else {
  468. var buffer = fMp4Encoder.EncoderVideo(package, encoderInfo, false);
  469. fileStream.Write(buffer);
  470. }
  471. }
  472. fileStream.Close();
  473. }
  474. [Fact]
  475. public void Test4()
  476. {
  477. FMp4EncoderInfo encoderInfo = new FMp4EncoderInfo();
  478. FMp4Encoder fMp4Encoder = new FMp4Encoder();
  479. H264Decoder h264Decoder = new H264Decoder();
  480. var packages = ParseNALUTests();
  481. var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_5.mp4");
  482. if (File.Exists(filepath))
  483. {
  484. File.Delete(filepath);
  485. }
  486. using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
  487. var ftyp = fMp4Encoder.EncoderFtypBox();
  488. encoderInfo.SampleSize += (uint)ftyp.Length;
  489. fileStream.Write(ftyp);
  490. var iNalus = h264Decoder.ParseNALU(packages[0]);
  491. //判断第一帧是否关键帧
  492. var moov = fMp4Encoder.EncoderMoovBox(
  493. iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS),
  494. iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS));
  495. encoderInfo.SampleSize += (uint)moov.Length;
  496. fileStream.Write(moov);
  497. List<H264NALU> nalus = new List<H264NALU>();
  498. foreach (var package in packages)
  499. {
  500. List<H264NALU> h264NALUs = h264Decoder.ParseNALU(package);
  501. foreach (var nalu in h264NALUs)
  502. {
  503. if (nalu.Slice)
  504. {
  505. //H264 NALU slice first_mb_in_slice
  506. nalus.Add(nalu);
  507. }
  508. else
  509. {
  510. if (nalus.Count > 0)
  511. {
  512. var otherBuffer = fMp4Encoder.EncoderOtherVideoBox(nalus, encoderInfo);
  513. encoderInfo.SampleSize += (uint)otherBuffer.Length;
  514. fileStream.Write(otherBuffer);
  515. nalus.Clear();
  516. }
  517. nalus.Add(nalu);
  518. }
  519. }
  520. }
  521. fileStream.Close();
  522. }
  523. [Fact]
  524. public void tkhd_width_height_test()
  525. {
  526. //01 60 00 00
  527. //01 20 00 00
  528. var a = BinaryPrimitives.ReadUInt32LittleEndian(new byte[] { 0x01, 0x60, 0, 0 });
  529. var b = BinaryPrimitives.ReadUInt32LittleEndian(new byte[] { 0x01, 0x20, 0, 0 });
  530. //00 00 01 60
  531. //00 00 01 20
  532. var c = BinaryPrimitives.ReadUInt32BigEndian(new byte[] { 0, 0, 0x01, 0x20 });
  533. var d = BinaryPrimitives.ReadUInt32BigEndian(new byte[] { 0, 0, 0x01, 0x60 });
  534. var e = new byte[4];
  535. var f = new byte[4];
  536. BinaryPrimitives.WriteUInt32LittleEndian(e, 352);
  537. BinaryPrimitives.WriteUInt32LittleEndian(f, 288);
  538. //60 01 00 00
  539. //20 01 00 00
  540. var g = e.ToHexString();
  541. var h = f.ToHexString();
  542. }
  543. [Fact]
  544. public void tfdt_test()
  545. {
  546. var TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
  547. TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = 0;
  548. FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[65535]);
  549. TrackFragmentBaseMediaDecodeTimeBox.ToBuffer(ref writer);
  550. var buffer = writer.FlushAndGetArray().ToHexString();
  551. }
  552. [Fact]
  553. public void match_test()
  554. {
  555. var filepath1 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_1.mp4");
  556. var filepath2 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_1_fragmented.mp4");
  557. var byte1 = File.ReadAllBytes(filepath1);
  558. var byte2 = File.ReadAllBytes(filepath2);
  559. if (byte1.Length == byte2.Length)
  560. {
  561. for (var i = 0; i < byte1.Length; i++)
  562. {
  563. if (byte1[i] != byte2[i])
  564. {
  565. }
  566. }
  567. }
  568. }
  569. public JT1078Package ParseNALUTest()
  570. {
  571. JT1078Package Package = null;
  572. var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_3.txt"));
  573. int mergeBodyLength = 0;
  574. foreach (var line in lines)
  575. {
  576. var data = line.Split(',');
  577. var bytes = data[6].ToHexBytes();
  578. JT1078Package package = JT1078Serializer.Deserialize(bytes);
  579. mergeBodyLength += package.DataBodyLength;
  580. Package = JT1078Serializer.Merge(package);
  581. }
  582. return Package;
  583. }
  584. public List<JT1078Package> ParseNALUTests()
  585. {
  586. List<JT1078Package> packages = new List<JT1078Package>();
  587. var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_3.txt"));
  588. int mergeBodyLength = 0;
  589. foreach (var line in lines)
  590. {
  591. var data = line.Split(',');
  592. var bytes = data[6].ToHexBytes();
  593. JT1078Package package = JT1078Serializer.Deserialize(bytes);
  594. mergeBodyLength += package.DataBodyLength;
  595. var packageMerge = JT1078Serializer.Merge(package);
  596. if (packageMerge != null)
  597. {
  598. packages.Add(packageMerge);
  599. }
  600. }
  601. return packages;
  602. }
  603. public List<JT1078Package> ParseNALUTests1()
  604. {
  605. List<JT1078Package> packages = new List<JT1078Package>();
  606. var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "1078视频数据.txt"));
  607. int mergeBodyLength = 0;
  608. foreach (var line in lines)
  609. {
  610. var data = line.Split(',');
  611. var bytes = data[1].ToHexBytes();
  612. JT1078Package package = JT1078Serializer.Deserialize(bytes);
  613. mergeBodyLength += package.DataBodyLength;
  614. var packageMerge = JT1078Serializer.Merge(package);
  615. if (packageMerge != null)
  616. {
  617. packages.Add(packageMerge);
  618. }
  619. }
  620. return packages;
  621. }
  622. }
  623. }