@@ -2,9 +2,10 @@ ffmpeg -i demo.mp4 -c copy -f flv -vcodec h264 -acodec aac demo_flv.flv | |||||
./ffmpeg -i JT1078_3.h264 -r 25 -c copy -f flv "D:\JT1078_3.flv" | ./ffmpeg -i JT1078_3.h264 -r 25 -c copy -f flv "D:\JT1078_3.flv" | ||||
ffmpeg -f dshow -i video="USB2.0 PC CAMERA" -t 60 -c copy -f h264 -vcodec h264 jt1078.264 | |||||
ffmpeg -f dshow -i video="USB2.0 PC CAMERA" -t 60 -c copy -f h264 -vcodec h264 ipc.264 | |||||
ffmpeg -i demo.264 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov fragmented_demo.mp4 | ffmpeg -i demo.264 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov fragmented_demo.mp4 | ||||
ffmpeg -i ipc.264 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov ipc_fragmented_demo.mp4 | |||||
chrome://media-internals/ | chrome://media-internals/ |
@@ -22,6 +22,7 @@ | |||||
<ItemGroup> | <ItemGroup> | ||||
<ProjectReference Include="..\JT1078.FMp4\JT1078.FMp4.csproj" /> | <ProjectReference Include="..\JT1078.FMp4\JT1078.FMp4.csproj" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<None Include="..\..\doc\video\fragmented_demo_mdat.txt" Link="FMP4\fragmented_demo_mdat.txt"> | <None Include="..\..\doc\video\fragmented_demo_mdat.txt" Link="FMP4\fragmented_demo_mdat.txt"> | ||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
@@ -30,6 +31,7 @@ | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
</None> | </None> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<None Update="FMP4\fragmented_demo_mdat.txt"> | <None Update="FMP4\fragmented_demo_mdat.txt"> | ||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
@@ -38,5 +40,17 @@ | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
</None> | </None> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<None Include="..\..\doc\video\jt1078_3.txt" Link="H264\jt1078_3.txt"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
<None Include="..\..\doc\video\jt1078_1.txt" Link="H264\jt1078_1.txt"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
<None Include="..\..\doc\video\jt1078_2.txt" Link="H264\jt1078_2.txt"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
</ItemGroup> | |||||
</Project> | </Project> |
@@ -0,0 +1,119 @@ | |||||
using JT1078.FMp4.Enums; | |||||
using JT1078.FMp4.Samples; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
namespace JT1078.FMp4.Test | |||||
{ | |||||
public class JT1078ToFMp4Box_Test | |||||
{ | |||||
[Fact] | |||||
public void Test1() | |||||
{ | |||||
//ftyp | |||||
FileTypeBox fileTypeBox = new FileTypeBox(); | |||||
fileTypeBox.MajorBrand = "isom"; | |||||
fileTypeBox.MinorVersion = "\0\0\0\u0001"; | |||||
fileTypeBox.CompatibleBrands.Add("isom"); | |||||
fileTypeBox.CompatibleBrands.Add("avc1"); | |||||
//moov | |||||
MovieBox movieBox = new MovieBox(); | |||||
movieBox.MovieHeaderBox = new MovieHeaderBox(1, 0); | |||||
movieBox.MovieHeaderBox.CreationTime = 2; | |||||
movieBox.MovieHeaderBox.ModificationTime = 3; | |||||
//var upperWordDuration = Math.floor(duration / (UINT32_MAX + 1)); | |||||
//var lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1)); | |||||
//movieBox.MovieHeaderBox.Duration= | |||||
//movieBox.MovieHeaderBox.Timescale= | |||||
movieBox.TrackBox = new TrackBox(); | |||||
movieBox.TrackBox.TrackHeaderBox = new TrackHeaderBox(1, 7); | |||||
movieBox.TrackBox.TrackHeaderBox.CreationTime = 2; | |||||
movieBox.TrackBox.TrackHeaderBox.ModificationTime = 3; | |||||
movieBox.TrackBox.TrackHeaderBox.TrackID = movieBox.MovieHeaderBox.NextTrackID; | |||||
//duration = track.duration * track.timescale, | |||||
//upperWordDuration = Math.floor(duration / (UINT32_MAX + 1)), | |||||
//lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1)); | |||||
//movieBox.TrackBox.TrackHeaderBox.Duration= | |||||
//movieBox.TrackBox.TrackHeaderBox.Timescale= | |||||
movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false; | |||||
//movieBox.TrackBox.TrackHeaderBox.Width= | |||||
//movieBox.TrackBox.TrackHeaderBox.Height= | |||||
movieBox.TrackBox.MediaBox = new MediaBox(); | |||||
movieBox.TrackBox.MediaBox.MediaHeaderBox = new MediaHeaderBox(); | |||||
//duration *= timescale; | |||||
//var upperWordDuration = Math.floor(duration / (UINT32_MAX + 1)); | |||||
//var lowerWordDuration = Math.floor(duration % (UINT32_MAX + 1)); | |||||
movieBox.TrackBox.MediaBox.MediaHeaderBox.CreationTime = 2; | |||||
movieBox.TrackBox.MediaBox.MediaHeaderBox.ModificationTime = 3; | |||||
//movieBox.TrackBox.MediaBox.MediaHeaderBox.Timescale= | |||||
//movieBox.TrackBox.MediaBox.MediaHeaderBox.Duration= | |||||
movieBox.TrackBox.MediaBox.HandlerBox = new HandlerBox(); | |||||
movieBox.TrackBox.MediaBox.HandlerBox.HandlerType = HandlerType.vide; | |||||
movieBox.TrackBox.MediaBox.HandlerBox.Name = "VideoHandler"; | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox = new MediaInformationBox(); | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.VideoMediaHeaderBox = new VideoMediaHeaderBox(); | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox = new DataInformationBox(); | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox = new DataReferenceBox(); | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List<DataEntryBox>(); | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1)); | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox(); | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox(movieBox.TrackBox.MediaBox.HandlerBox.HandlerType); | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List<SampleEntry>(); | |||||
AVC1SampleEntry avc1 = new AVC1SampleEntry(); | |||||
avc1.AVCConfigurationBox = new AVCConfigurationBox(); | |||||
//h264 | |||||
//avc1.Width= | |||||
//avc1.Height= | |||||
//avc1.AVCConfigurationBox.AVCLevelIndication | |||||
//avc1.AVCConfigurationBox.AVCProfileIndication | |||||
//avc1.AVCConfigurationBox.PPSs | |||||
//avc1.AVCConfigurationBox.SPSs | |||||
//avc1.AVCConfigurationBox.ProfileCompatibility | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries.Add(avc1); | |||||
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.TimeToSampleBox = new TimeToSampleBox(); | |||||
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 = movieBox.MovieHeaderBox.NextTrackID; | |||||
trex.DefaultSampleDescriptionIndex = 1; | |||||
trex.DefaultSampleDuration = 0; | |||||
trex.DefaultSampleSize = 0; | |||||
trex.DefaultSampleFlags = 1; | |||||
movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex); | |||||
//fragment moof n | |||||
List<FragmentBox> moofs = new List<FragmentBox>(); | |||||
FragmentBox fragmentBox = new FragmentBox(); | |||||
fragmentBox.MovieFragmentBox = new MovieFragmentBox(); | |||||
fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox(); | |||||
//fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox.SequenceNumber=SN | |||||
fragmentBox.MovieFragmentBox.TrackFragmentBox = new TrackFragmentBox(); | |||||
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(); | |||||
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = movieBox.MovieHeaderBox.NextTrackID; | |||||
fragmentBox.MovieFragmentBox.TrackFragmentBox.SampleDependencyTypeBox = new SampleDependencyTypeBox(); | |||||
fragmentBox.MovieFragmentBox.TrackFragmentBox.SampleDependencyTypeBox.SampleDependencyTypes = new List<SampleDependencyTypeBox.SampleDependencyType>(); | |||||
//todo:fragmentBox.MovieFragmentBox.TrackFragmentBox.SampleDependencyTypeBox.SampleDependencyTypes | |||||
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox(); | |||||
//upperWordBaseMediaDecodeTime = Math.floor(baseMediaDecodeTime / (UINT32_MAX + 1)), | |||||
//lowerWordBaseMediaDecodeTime = Math.floor(baseMediaDecodeTime % (UINT32_MAX + 1)); | |||||
//fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime | |||||
//trun | |||||
fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(); | |||||
moofs.Add(fragmentBox); | |||||
//mfra | |||||
} | |||||
} | |||||
} |
@@ -6,6 +6,9 @@ using System.Text; | |||||
namespace JT1078.FMp4 | namespace JT1078.FMp4 | ||||
{ | { | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
public class FragmentBox:IFMp4MessagePackFormatter | public class FragmentBox:IFMp4MessagePackFormatter | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
@@ -16,7 +19,10 @@ namespace JT1078.FMp4 | |||||
/// mdat | /// mdat | ||||
/// </summary> | /// </summary> | ||||
public MediaDataBox MediaDataBox { get; set; } | public MediaDataBox MediaDataBox { get; set; } | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="writer"></param> | |||||
public void ToBuffer(ref FMp4MessagePackWriter writer) | public void ToBuffer(ref FMp4MessagePackWriter writer) | ||||
{ | { | ||||
if (MovieFragmentBox != null) | if (MovieFragmentBox != null) | ||||
@@ -16,7 +16,7 @@ namespace JT1078.FMp4 | |||||
/// </summary> | /// </summary> | ||||
/// <param name="version"></param> | /// <param name="version"></param> | ||||
/// <param name="flags"></param> | /// <param name="flags"></param> | ||||
public MediaHeaderBox(byte version, uint flags=0) : base("mdhd", version, flags) | |||||
public MediaHeaderBox(byte version=1, uint flags=0) : base("mdhd", version, flags) | |||||
{ | { | ||||
} | } | ||||
public ulong CreationTime { get; set; } | public ulong CreationTime { get; set; } | ||||
@@ -16,7 +16,7 @@ namespace JT1078.FMp4 | |||||
/// </summary> | /// </summary> | ||||
/// <param name="version"></param> | /// <param name="version"></param> | ||||
/// <param name="flags"></param> | /// <param name="flags"></param> | ||||
public MovieHeaderBox(byte version, uint flags=0) : base("mvhd", version, flags) | |||||
public MovieHeaderBox(byte version=1, uint flags=0) : base("mvhd", version, flags) | |||||
{ | { | ||||
} | } | ||||
public ulong CreationTime { get; set; } | public ulong CreationTime { get; set; } | ||||
@@ -30,13 +30,14 @@ namespace JT1078.FMp4 | |||||
/// </summary> | /// </summary> | ||||
public CompositionOffsetBox CompositionOffsetBox { get; set; } | public CompositionOffsetBox CompositionOffsetBox { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// stsc | |||||
/// </summary> | |||||
public SampleToChunkBox SampleToChunkBox { get; set; } | |||||
/// <summary> | |||||
/// stsz | /// stsz | ||||
/// </summary> | /// </summary> | ||||
public SampleSizeBox SampleSizeBox { get; set; } | public SampleSizeBox SampleSizeBox { get; set; } | ||||
/// <summary> | |||||
/// stsc | |||||
/// </summary> | |||||
public SampleToChunkBox SampleToChunkBox { get; set; } | |||||
//public CompactSampleSizeBox CompactSampleSizeBox { get; set; } | //public CompactSampleSizeBox CompactSampleSizeBox { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// stco | /// stco | ||||
@@ -8,6 +8,15 @@ namespace JT1078.FMp4 | |||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// fmp4 | /// fmp4 | ||||
/// stream data | |||||
/// ftyp | |||||
/// moov | |||||
/// moof 1 | |||||
/// mdat 1 | |||||
/// ... | |||||
/// moof n | |||||
/// mdat n | |||||
/// mfra | |||||
/// </summary> | /// </summary> | ||||
public class FMp4Box:IFMp4MessagePackFormatter | public class FMp4Box:IFMp4MessagePackFormatter | ||||
{ | { | ||||
@@ -27,7 +36,10 @@ namespace JT1078.FMp4 | |||||
/// mfra | /// mfra | ||||
/// </summary> | /// </summary> | ||||
public MovieFragmentRandomAccessBox MovieFragmentRandomAccessBox { get; set; } | public MovieFragmentRandomAccessBox MovieFragmentRandomAccessBox { get; set; } | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
/// <param name="writer"></param> | |||||
public void ToBuffer(ref FMp4MessagePackWriter writer) | public void ToBuffer(ref FMp4MessagePackWriter writer) | ||||
{ | { | ||||
FileTypeBox.ToBuffer(ref writer); | FileTypeBox.ToBuffer(ref writer); | ||||
@@ -175,6 +175,11 @@ | |||||
4位*n | 4位*n | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="T:JT1078.FMp4.FragmentBox"> | |||||
<summary> | |||||
</summary> | |||||
</member> | |||||
<member name="P:JT1078.FMp4.FragmentBox.MovieFragmentBox"> | <member name="P:JT1078.FMp4.FragmentBox.MovieFragmentBox"> | ||||
<summary> | <summary> | ||||
moof | moof | ||||
@@ -185,6 +190,12 @@ | |||||
mdat | mdat | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="M:JT1078.FMp4.FragmentBox.ToBuffer(JT1078.FMp4.MessagePack.FMp4MessagePackWriter@)"> | |||||
<summary> | |||||
</summary> | |||||
<param name="writer"></param> | |||||
</member> | |||||
<member name="P:JT1078.FMp4.FreeSpaceBox.FillValue"> | <member name="P:JT1078.FMp4.FreeSpaceBox.FillValue"> | ||||
<summary> | <summary> | ||||
填充值 | 填充值 | ||||
@@ -1045,6 +1056,15 @@ | |||||
<member name="T:JT1078.FMp4.FMp4Box"> | <member name="T:JT1078.FMp4.FMp4Box"> | ||||
<summary> | <summary> | ||||
fmp4 | fmp4 | ||||
stream data | |||||
ftyp | |||||
moov | |||||
moof 1 | |||||
mdat 1 | |||||
... | |||||
moof n | |||||
mdat n | |||||
mfra | |||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="P:JT1078.FMp4.FMp4Box.FileTypeBox"> | <member name="P:JT1078.FMp4.FMp4Box.FileTypeBox"> | ||||
@@ -1067,6 +1087,12 @@ | |||||
mfra | mfra | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="M:JT1078.FMp4.FMp4Box.ToBuffer(JT1078.FMp4.MessagePack.FMp4MessagePackWriter@)"> | |||||
<summary> | |||||
</summary> | |||||
<param name="writer"></param> | |||||
</member> | |||||
<member name="F:JT1078.FMp4.FMp4Constants.DateLimitYear"> | <member name="F:JT1078.FMp4.FMp4Constants.DateLimitYear"> | ||||
<summary> | <summary> | ||||
日期限制于2000年 | 日期限制于2000年 | ||||
@@ -1186,6 +1212,11 @@ | |||||
</summary> | </summary> | ||||
<param name="language"></param> | <param name="language"></param> | ||||
</member> | </member> | ||||
<member name="T:JT1078.FMp4.Mp4Box"> | |||||
<summary> | |||||
</summary> | |||||
</member> | |||||
<member name="P:JT1078.FMp4.Mp4Box.Size"> | <member name="P:JT1078.FMp4.Mp4Box.Size"> | ||||
<summary> | <summary> | ||||
盒子大小 | 盒子大小 | ||||
@@ -6,6 +6,9 @@ using System.Text; | |||||
namespace JT1078.FMp4 | namespace JT1078.FMp4 | ||||
{ | { | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
public abstract class Mp4Box | public abstract class Mp4Box | ||||
{ | { | ||||
//public const string UUID = "uuid"; | //public const string UUID = "uuid"; | ||||
@@ -10,7 +10,7 @@ namespace JT1078.FMp4.Samples | |||||
/// </summary> | /// </summary> | ||||
public abstract class VisualSampleEntry : SampleEntry | public abstract class VisualSampleEntry : SampleEntry | ||||
{ | { | ||||
const string COMPRESSORNAME = "jt1078&SmallChi(koike)&TK"; | |||||
const string COMPRESSORNAME = "jt1078&SmallChi(Koike)&TK"; | |||||
/// <summary> | /// <summary> | ||||
/// VisualSampleEntry | /// VisualSampleEntry | ||||
/// </summary> | /// </summary> | ||||