diff --git a/util/MP4/Makefile b/util/MP4/Makefile new file mode 100644 index 00000000..4ff1d185 --- /dev/null +++ b/util/MP4/Makefile @@ -0,0 +1,18 @@ +SRC = box_abst.cpp box_afra.cpp box_afrt.cpp box_amhp.cpp box_asrt.cpp box_avcC.cpp box.cpp box_dinf.cpp box_dref.cpp box_esds.cpp box_ftyp.cpp box_hdlr.cpp box_hmhd.cpp box_mdat.cpp box_mdhd.cpp box_mdia.cpp box_mfhd.cpp box_minf.cpp box_moof.cpp box_moov.cpp box_mvex.cpp box_mvhd.cpp box_nmhd.cpp box_rtmp.cpp box_smhd.cpp box_stbl.cpp box_stco.cpp box_stsc.cpp box_stsd.cpp box_stts.cpp box_tfhd.cpp box_tkhd.cpp box_traf.cpp box_trak.cpp box_trex.cpp box_trun.cpp box_url.cpp box_vmhd.cpp interface.cpp main.cpp +OBJ = $(SRC:.cpp=.o) +OUT = Boxtest +INCLUDES = +CCFLAGS = -Wall -Wextra -funsigned-char -g +CC = $(CROSS)g++ +LD = $(CROSS)ld +AR = $(CROSS)ar +LIBS = +.SUFFIXES: .cpp +.PHONY: clean default +default: $(OUT) +.cpp.o: + $(CC) $(INCLUDES) $(CCFLAGS) $(LIBS) -c $< -o $@ +$(OUT): $(OBJ) + $(CC) $(LIBS) -o $(OUT) $(OBJ) +clean: + rm -rf $(OBJ) $(OUT) Makefile.bak *~ diff --git a/util/MP4/box.cpp b/util/MP4/box.cpp new file mode 100644 index 00000000..458ba15d --- /dev/null +++ b/util/MP4/box.cpp @@ -0,0 +1,150 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +struct BoxHeader { + uint32_t TotalSize; + uint32_t BoxType; +};//BoxHeader struct + +class Box { + public: + Box(); + Box(uint32_t BoxType); + ~Box(); + void SetBoxType(uint32_t BoxType); + uint32_t GetBoxType(); + void SetPayload(uint32_t Size, uint8_t * Data, uint32_t Index = 0); + uint32_t GetPayloadSize(); + uint8_t * GetPayload(); + uint8_t * GetPayload(uint32_t Index, uint32_t & Size); + uint32_t GetBoxedDataSize(); + uint8_t * GetBoxedData( ); + static uint8_t * uint32_to_uint8( uint32_t data ); + static uint8_t * uint16_to_uint8( uint16_t data ); + static uint8_t * uint8_to_uint8( uint8_t data ); + BoxHeader GetHeader( ); + void ResetPayload( ); + private: + BoxHeader header; + uint8_t * Payload; + uint32_t PayloadSize; +};//Box Class + +Box::Box() { + Payload = NULL; + PayloadSize = 0; +} + +Box::Box(uint32_t BoxType) { + header.BoxType = BoxType; + Payload = NULL; + PayloadSize = 0; +} + +Box::~Box() { +} + +void Box::SetBoxType(uint32_t BoxType) { + header.BoxType = BoxType; +} + +uint32_t Box::GetBoxType() { + return header.BoxType; +} + +void Box::SetPayload(uint32_t Size, uint8_t * Data, uint32_t Index) { + uint8_t * tempchar = NULL; + if ( Index + Size > PayloadSize ) { + if ( Payload ) { + tempchar = new uint8_t[PayloadSize]; + memcpy( tempchar, Payload, PayloadSize ); + delete Payload; + } + PayloadSize = Index + Size; + Payload = new uint8_t[PayloadSize]; + if( tempchar ) { + memcpy( Payload, tempchar, Index ); + } else { + for(uint32_t i = 0; i < Index; i++) { Payload[i] = 0; } + } + memcpy( &Payload[Index], Data, Size ); + header.TotalSize = PayloadSize + 8; + if( tempchar ) { + delete tempchar; + } + } else { + memcpy( &Payload[Index], Data, Size ); + } +} + +uint32_t Box::GetPayloadSize() { + return PayloadSize; +} + +uint8_t * Box::GetPayload() { + uint8_t * temp = new uint8_t[PayloadSize]; + memcpy( temp, Payload, PayloadSize ); + return temp; +} + +uint8_t * Box::GetPayload(uint32_t Index, uint32_t & Size) { + if(Index > PayloadSize) { return NULL; } + if(Index + Size > PayloadSize) { Size = PayloadSize - Index; } + uint8_t * temp = new uint8_t[Size - Index]; + memcpy( temp, &Payload[Index], Size - Index ); + return temp; +} + +uint32_t Box::GetBoxedDataSize() { + return header.TotalSize; +} + +uint8_t * Box::GetBoxedData( ) { + uint8_t * temp = new uint8_t[header.TotalSize]; + memcpy( temp, uint32_to_uint8(header.TotalSize), 4 ); + memcpy( &temp[4], uint32_to_uint8(header.BoxType), 4 ); + memcpy( &temp[8], Payload, PayloadSize ); + return temp; +} + + +uint8_t * Box::uint32_to_uint8( uint32_t data ) { + uint8_t * temp = new uint8_t[4]; + temp[0] = (data >> 24) & 0x000000FF; + temp[1] = (data >> 16 ) & 0x000000FF; + temp[2] = (data >> 8 ) & 0x000000FF; + temp[3] = (data ) & 0x000000FF; + return temp; +} + +uint8_t * Box::uint16_to_uint8( uint16_t data ) { + uint8_t * temp = new uint8_t[2]; + temp[0] = (data >> 8) & 0x00FF; + temp[1] = (data ) & 0x00FF; + return temp; +} + +uint8_t * Box::uint8_to_uint8( uint8_t data ) { + uint8_t * temp = new uint8_t[1]; + temp[0] = data; + return temp; +} + +BoxHeader Box::GetHeader( ) { + return header; +} + +void Box::ResetPayload( ) { + header.TotalSize -= PayloadSize; + PayloadSize = 0; + if(Payload) { + delete Payload; + Payload = NULL; + } +} diff --git a/util/MP4/box_abst.cpp b/util/MP4/box_abst.cpp new file mode 100644 index 00000000..be97f99a --- /dev/null +++ b/util/MP4/box_abst.cpp @@ -0,0 +1,218 @@ +#include "box.cpp" +#include +#include + +struct abst_serverentry { + std::string ServerBaseUrl; +};//abst_serverentry + +struct abst_qualityentry { + std::string QualityModifier; +};//abst_qualityentry + +class Box_abst { + public: + Box_abst( ); + ~Box_abst(); + Box * GetBox(); + void SetBootstrapVersion( uint32_t Version = 1 ); + void SetProfile( uint8_t Profile = 0 ); + void SetLive( bool Live = true ); + void SetUpdate( bool Update = false ); + void SetTimeScale( uint32_t Scale = 1000 ); + void SetMediaTime( uint32_t Time = 0 ); + void SetSMPTE( uint32_t Smpte = 0 ); + void SetMovieIdentifier( std::string Identifier = "" ); + void SetDRM( std::string Drm = "" ); + void SetMetaData( std::string MetaData = "" ); + void AddServerEntry( std::string Url = "", uint32_t Offset = 0 ); + void AddQualityEntry( std::string Quality = "", uint32_t Offset = 0 ); + void AddSegmentRunTable( Box * newSegment, uint32_t Offset = 0 ); + void AddFragmentRunTable( Box * newFragment, uint32_t Offset = 0 ); + void WriteContent( ); + private: + void SetDefaults( ); + void SetReserved( ); + uint32_t curBootstrapInfoVersion; + uint8_t curProfile; + bool isLive; + bool isUpdate; + uint32_t curTimeScale; + uint32_t curMediatime;//write as uint64_t + uint32_t curSMPTE;//write as uint64_t + std::string curMovieIdentifier; + std::string curDRM; + std::string curMetaData; + std::vector Servers; + std::vector Qualities; + std::vector SegmentRunTables; + std::vector FragmentRunTables; + Box * Container; +};//Box_ftyp Class + +Box_abst::Box_abst( ) { + Container = new Box( 0x61627374 ); +} + +Box_abst::~Box_abst() { + delete Container; +} + +Box * Box_abst::GetBox() { + return Container; +} + +void Box_abst::SetBootstrapVersion( uint32_t Version ) { + curBootstrapInfoVersion = Version; +} + +void Box_abst::SetProfile( uint8_t Profile ) { + curProfile = Profile; +} + +void Box_abst::SetLive( bool Live ) { + isLive = Live; +} + +void Box_abst::SetUpdate( bool Update ) { + isUpdate = Update; +} + +void Box_abst::SetTimeScale( uint32_t Scale ) { + curTimeScale = Scale; +} + +void Box_abst::SetMediaTime( uint32_t Time ) { + curMediatime = Time; +} + +void Box_abst::SetSMPTE( uint32_t Smpte ) { + curSMPTE = Smpte; +} + +void Box_abst::SetMovieIdentifier( std::string Identifier ) { + curMovieIdentifier = Identifier; +} + +void Box_abst::SetDRM( std::string Drm ) { + curDRM = Drm; +} + +void Box_abst::SetMetaData( std::string MetaData ) { + curMetaData = MetaData; +} + +void Box_abst::AddServerEntry( std::string Url, uint32_t Offset ) { + if(Offset >= Servers.size()) { + Servers.resize(Offset+1); + } + Servers[Offset].ServerBaseUrl = Url; +} + +void Box_abst::AddQualityEntry( std::string Quality, uint32_t Offset ) { + if(Offset >= Qualities.size()) { + Qualities.resize(Offset+1); + } + Qualities[Offset].QualityModifier = Quality; +} + +void Box_abst::AddSegmentRunTable( Box * newSegment, uint32_t Offset ) { + if( Offset >= SegmentRunTables.size() ) { + SegmentRunTables.resize(Offset+1); + } + if( SegmentRunTables[Offset] ) { + delete SegmentRunTables[Offset]; + } + SegmentRunTables[Offset] = newSegment; +} + +void Box_abst::AddFragmentRunTable( Box * newFragment, uint32_t Offset ) { + if( Offset >= FragmentRunTables.size() ) { + FragmentRunTables.resize(Offset+1); + } + if( FragmentRunTables[Offset] ) { + delete FragmentRunTables[Offset]; + } + FragmentRunTables[Offset] = newFragment; +} + + +void Box_abst::SetDefaults( ) { + SetProfile( ); + SetLive( ); + SetUpdate( ); + SetTimeScale( ); + SetMediaTime( ); + SetSMPTE( ); + SetMovieIdentifier( ); + SetDRM( ); + SetMetaData( ); +} + +void Box_abst::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_abst::WriteContent( ) { + Box * current; + std::string serializedServers = ""; + std::string serializedQualities = ""; + std::string serializedSegments = ""; + std::string serializedFragments = ""; + int SegmentAmount = 0; + int FragmentAmount = 0; + uint8_t * temp = new uint8_t[1]; + + Container->ResetPayload( ); + SetReserved( ); + + for( uint32_t i = 0; i < Servers.size(); i++ ) { + serializedServers.append(Servers[i].ServerBaseUrl.c_str()); + serializedServers += '\0'; + } + for( uint32_t i = 0; i < Qualities.size(); i++ ) { + serializedQualities.append(Qualities[i].QualityModifier.c_str()); + serializedQualities += '\0'; + } + for( uint32_t i = 0; i < SegmentRunTables.size(); i++ ) { + current=SegmentRunTables[i]; + if( current ) { + SegmentAmount ++; + serializedSegments.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + for( uint32_t i = 0; i < FragmentRunTables.size(); i++ ) { + current=FragmentRunTables[i]; + if( current ) { + FragmentAmount ++; + serializedFragments.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + uint32_t OffsetServerEntryCount = 29 + curMovieIdentifier.size() + 1; + uint32_t OffsetQualityEntryCount = OffsetServerEntryCount + 4 + serializedServers.size(); + uint32_t OffsetDrmData = OffsetQualityEntryCount + 4 + serializedQualities.size(); + uint32_t OffsetMetaData = OffsetDrmData + curDRM.size() + 1; + uint32_t OffsetSegmentRuntableCount = OffsetMetaData + curMetaData.size() + 1; + uint32_t OffsetFragmentRuntableCount = OffsetSegmentRuntableCount + 4 + serializedSegments.size(); + + temp[0] = 0 & ( curProfile << 6 ) & ( (uint8_t)isLive << 7 ) & ( (uint8_t)isUpdate << 7 ); + + Container->SetPayload((uint32_t)serializedFragments.size(),(uint8_t*)serializedFragments.c_str(),OffsetFragmentRuntableCount+4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(FragmentAmount),OffsetFragmentRuntableCount); + Container->SetPayload((uint32_t)serializedSegments.size(),(uint8_t*)serializedSegments.c_str(),OffsetSegmentRuntableCount+4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(SegmentAmount),OffsetSegmentRuntableCount); + Container->SetPayload((uint32_t)curMetaData.size()+1,(uint8_t*)curMetaData.c_str(),OffsetMetaData); + Container->SetPayload((uint32_t)curDRM.size()+1,(uint8_t*)curDRM.c_str(),OffsetDrmData); + Container->SetPayload((uint32_t)serializedQualities.size(),(uint8_t*)serializedQualities.c_str(),OffsetQualityEntryCount+4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Qualities.size()),OffsetQualityEntryCount); + Container->SetPayload((uint32_t)serializedServers.size(),(uint8_t*)serializedServers.c_str(),OffsetServerEntryCount+4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Servers.size()),OffsetServerEntryCount); + Container->SetPayload((uint32_t)curMovieIdentifier.size()+1,(uint8_t*)curMovieIdentifier.c_str(),29);//+1 for \0-terminated string... + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curSMPTE),25); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),21); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curMediatime),17); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),13); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curTimeScale),9); + Container->SetPayload((uint32_t)1,temp,8); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curBootstrapInfoVersion),4); +} diff --git a/util/MP4/box_afra.cpp b/util/MP4/box_afra.cpp new file mode 100644 index 00000000..103c2c40 --- /dev/null +++ b/util/MP4/box_afra.cpp @@ -0,0 +1,75 @@ +#include "box.cpp" +#include + +struct afra_record { + uint32_t Time; + uint32_t Offset; +};//afra_record + +class Box_afra { + public: + Box_afra( ); + ~Box_afra(); + Box * GetBox(); + void SetTimeScale( uint32_t Scale = 1 ); + void AddEntry( uint32_t Time = 0, uint32_t SampleOffset = 0, uint32_t Offset = 0 ); + void WriteContent( ); + private: + void SetReserved( ); + void SetDefaults( ); + + Box * Container; + uint32_t CurrentTimeScale; + std::vector Entries; +};//Box_ftyp Class + +Box_afra::Box_afra( ) { + Container = new Box( 0x61667261 ); + SetReserved( ); + SetDefaults( ); +} + +Box_afra::~Box_afra() { + delete Container; +} + +Box * Box_afra::GetBox() { + return Container; +} + +void Box_afra::SetDefaults( ) { + SetTimeScale( ); +} + +void Box_afra::SetReserved( ) { + uint8_t * temp = new uint8_t[1]; + temp[0] = 0; + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),1); + Container->SetPayload((uint32_t)1,temp); +} + +void Box_afra::SetTimeScale( uint32_t Scale ) { + CurrentTimeScale = Scale; + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Scale),5); +} + +void Box_afra::AddEntry( uint32_t Time, uint32_t SampleOffset, uint32_t Offset ) { + if(Offset >= Entries.size()) { + Entries.resize(Offset+1); + } + Entries[Offset].Time = Time; + Entries[Offset].Offset = SampleOffset; +} + +void Box_afra::WriteContent( ) { + Container->ResetPayload(); + SetReserved( ); + if(!Entries.empty()) { + for(int32_t i = Entries.size() -1; i >= 0; i--) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].Offset),(i*12)+21); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].Time),(i*12)+17); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),(i*12)+13); + } + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries.size()),9); +} diff --git a/util/MP4/box_afrt.cpp b/util/MP4/box_afrt.cpp new file mode 100644 index 00000000..67365d7e --- /dev/null +++ b/util/MP4/box_afrt.cpp @@ -0,0 +1,100 @@ +#include "box.cpp" +#include +#include + +struct afrt_fragmentrunentry { + uint32_t FirstFragment; + uint32_t FirstFragmentTimestamp; //write as uint64_t + uint32_t FragmentDuration; + uint8_t DiscontinuityIndicator;//if FragmentDuration == 0 +};//afrt_fragmentrunentry + +class Box_afrt { + public: + Box_afrt( ); + ~Box_afrt(); + Box * GetBox(); + void SetUpdate( bool Update = false ); + void SetTimeScale( uint32_t Scale = 1000 ); + void AddQualityEntry( std::string Quality = "", uint32_t Offset = 0 ); + void AddFragmentRunEntry( uint32_t FirstFragment = 0, uint32_t FirstFragmentTimestamp = 0, uint32_t FragmentsDuration = 1, uint8_t Discontinuity = 0, uint32_t Offset = 0 ); + void WriteContent( ); + private: + void SetDefaults( ); + bool isUpdate; + uint32_t curTimeScale; + std::vector QualitySegmentUrlModifiers; + std::vector FragmentRunEntryTable; + Box * Container; +};//Box_ftyp Class + +Box_afrt::Box_afrt( ) { + Container = new Box( 0x61667274 ); +} + +Box_afrt::~Box_afrt() { + delete Container; +} + +Box * Box_afrt::GetBox() { + return Container; +} + +void Box_afrt::SetUpdate( bool Update ) { + isUpdate = Update; +} + +void Box_afrt::AddQualityEntry( std::string Quality, uint32_t Offset ) { + if(Offset >= QualitySegmentUrlModifiers.size()) { + QualitySegmentUrlModifiers.resize(Offset+1); + } + QualitySegmentUrlModifiers[Offset] = Quality; +} + +void Box_afrt::AddFragmentRunEntry( uint32_t FirstFragment, uint32_t FirstFragmentTimestamp, uint32_t FragmentsDuration, uint8_t Discontinuity, uint32_t Offset ) { + if( Offset >= FragmentRunEntryTable.size() ) { + FragmentRunEntryTable.resize(Offset+1); + } + FragmentRunEntryTable[Offset].FirstFragment = FirstFragment; + FragmentRunEntryTable[Offset].FirstFragmentTimestamp = FirstFragmentTimestamp; + FragmentRunEntryTable[Offset].FragmentDuration = FragmentsDuration; + FragmentRunEntryTable[Offset].DiscontinuityIndicator = Discontinuity; +} + +void Box_afrt::SetDefaults( ) { + SetUpdate( ); + SetTimeScale( ); +} + +void Box_afrt::SetTimeScale( uint32_t Scale ) { + curTimeScale = Scale; +} + +void Box_afrt::WriteContent( ) { + std::string serializedQualities = ""; + std::string serializedFragmentEntries = ""; + Container->ResetPayload( ); + + for( uint32_t i = 0; i < QualitySegmentUrlModifiers.size(); i++ ) { + serializedQualities.append(QualitySegmentUrlModifiers[i].c_str()); + serializedQualities += '\0'; + } + for( uint32_t i = 0; i < FragmentRunEntryTable.size(); i ++ ) { + serializedFragmentEntries.append((char*)Box::uint32_to_uint8(FragmentRunEntryTable[i].FirstFragment)); + serializedFragmentEntries.append((char*)Box::uint32_to_uint8(0)); + serializedFragmentEntries.append((char*)Box::uint32_to_uint8(FragmentRunEntryTable[i].FirstFragmentTimestamp)); + serializedFragmentEntries.append((char*)Box::uint32_to_uint8(FragmentRunEntryTable[i].FragmentDuration)); + if(FragmentRunEntryTable[i].FragmentDuration == 0) { + serializedFragmentEntries.append((char*)Box::uint8_to_uint8(FragmentRunEntryTable[i].DiscontinuityIndicator)); + } + } + + uint32_t OffsetFragmentRunEntryCount = 9 + serializedQualities.size(); + + Container->SetPayload((uint32_t)serializedFragmentEntries.size(),(uint8_t*)serializedFragmentEntries.c_str(),OffsetFragmentRunEntryCount+4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(FragmentRunEntryTable.size()),OffsetFragmentRunEntryCount); + Container->SetPayload((uint32_t)serializedQualities.size(),(uint8_t*)serializedQualities.c_str(),9); + Container->SetPayload((uint32_t)1,Box::uint8_to_uint8(QualitySegmentUrlModifiers.size()),8); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curTimeScale)); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8((isUpdate ? 1 : 0))); +} diff --git a/util/MP4/box_amhp.cpp b/util/MP4/box_amhp.cpp new file mode 100644 index 00000000..761da82a --- /dev/null +++ b/util/MP4/box_amhp.cpp @@ -0,0 +1,63 @@ +#include "box.cpp" +#include +#include + +struct amhp_record { + uint8_t HintTrackMode; + uint8_t Settings; + uint8_t TrailerDefaultSize; +};//stsc_record + +class Box_amhp { + public: + Box_amhp( ); + ~Box_amhp(); + Box * GetBox(); + void SetReserved( ); + void AddEntry( uint8_t HintTrackMode, uint8_t Settings, uint8_t TrailerDefaultSize, uint32_t Offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Entries; +};//Box_ftyp Class + +Box_amhp::Box_amhp( ) { + Container = new Box( 0x616D6870 ); + SetReserved(); +} + +Box_amhp::~Box_amhp() { + delete Container; +} + +Box * Box_amhp::GetBox() { + return Container; +} + +void Box_amhp::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_amhp::AddEntry( uint8_t HintTrackMode, uint8_t Settings, uint8_t TrailerDefaultSize, uint32_t Offset ) { + if(Offset >= Entries.size()) { + Entries.resize(Offset+1); + } + Entries[Offset].HintTrackMode = HintTrackMode; + Entries[Offset].Settings = Settings; + Entries[Offset].TrailerDefaultSize = TrailerDefaultSize; +} + + +void Box_amhp::WriteContent( ) { + Container->ResetPayload(); + SetReserved( ); + if(!Entries.empty()) { + for(int32_t i = Entries.size() -1; i >= 0; i--) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].TrailerDefaultSize),(i*12)+16); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].Settings),(i*12)+12); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].HintTrackMode),(i*12)+8); + } + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries.size()),4); +} diff --git a/util/MP4/box_asrt.cpp b/util/MP4/box_asrt.cpp new file mode 100644 index 00000000..a6ba2fbb --- /dev/null +++ b/util/MP4/box_asrt.cpp @@ -0,0 +1,81 @@ +#include "box.cpp" +#include +#include + +struct asrt_segmentrunentry { + uint32_t FirstSegment; + uint32_t FragmentsPerSegment; +};//abst_qualityentry + +class Box_asrt { + public: + Box_asrt( ); + ~Box_asrt(); + Box * GetBox(); + void SetUpdate( bool Update = false ); + void AddQualityEntry( std::string Quality = "", uint32_t Offset = 0 ); + void AddSegmentRunEntry( uint32_t FirstSegment = 0, uint32_t FragmentsPerSegment = 100, uint32_t Offset = 0 ); + void WriteContent( ); + private: + void SetDefaults( ); + bool isUpdate; + std::vector QualitySegmentUrlModifiers; + std::vector SegmentRunEntryTable; + Box * Container; +};//Box_ftyp Class + +Box_asrt::Box_asrt( ) { + Container = new Box( 0x61737274 ); +} + +Box_asrt::~Box_asrt() { + delete Container; +} + +Box * Box_asrt::GetBox() { + return Container; +} + +void Box_asrt::SetUpdate( bool Update ) { + isUpdate = Update; +} + +void Box_asrt::AddQualityEntry( std::string Quality, uint32_t Offset ) { + if(Offset >= QualitySegmentUrlModifiers.size()) { + QualitySegmentUrlModifiers.resize(Offset+1); + } + QualitySegmentUrlModifiers[Offset] = Quality; +} + +void Box_asrt::AddSegmentRunEntry( uint32_t FirstSegment, uint32_t FragmentsPerSegment, uint32_t Offset ) { + if( Offset >= SegmentRunEntryTable.size() ) { + SegmentRunEntryTable.resize(Offset+1); + } + SegmentRunEntryTable[Offset].FirstSegment = FirstSegment; + SegmentRunEntryTable[Offset].FragmentsPerSegment = FragmentsPerSegment; +} + +void Box_asrt::SetDefaults( ) { + SetUpdate( ); +} + +void Box_asrt::WriteContent( ) { + std::string serializedQualities = ""; + Container->ResetPayload( ); + + for( uint32_t i = 0; i < QualitySegmentUrlModifiers.size(); i++ ) { + serializedQualities.append(QualitySegmentUrlModifiers[i].c_str()); + serializedQualities += '\0'; + } + + uint32_t OffsetSegmentRunEntryCount = 5 + serializedQualities.size(); + + for( uint32_t i = 0; i < SegmentRunEntryTable.size(); i ++ ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(SegmentRunEntryTable[i].FragmentsPerSegment),(8*i)+OffsetSegmentRunEntryCount+8); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(SegmentRunEntryTable[i].FirstSegment),(8*i)+OffsetSegmentRunEntryCount+4); + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(SegmentRunEntryTable.size()),OffsetSegmentRunEntryCount); + Container->SetPayload((uint32_t)serializedQualities.size(),(uint8_t*)serializedQualities.c_str(),5); + Container->SetPayload((uint32_t)1,Box::uint8_to_uint8(QualitySegmentUrlModifiers.size()),4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8((isUpdate ? 1 : 0))); +} diff --git a/util/MP4/box_avcC.cpp b/util/MP4/box_avcC.cpp new file mode 100644 index 00000000..90bc6fe0 --- /dev/null +++ b/util/MP4/box_avcC.cpp @@ -0,0 +1,86 @@ +#include "box.cpp" +#include + +class Box_avcC { + public: + Box_avcC( ); + ~Box_avcC(); + Box * GetBox(); + void SetDataReferenceIndex( uint16_t DataReferenceIndex = 1 ); + void SetWidth( uint16_t Width = 0 ); + void SetHeight( uint16_t Height = 0 ); + void SetResolution ( uint32_t Horizontal = 0x00480000, uint32_t Vertical = 0x00480000 ); + void SetFrameCount ( uint16_t FrameCount = 1 ); + void SetCompressorName ( std::string CompressorName = ""); + void SetDepth ( uint16_t Depth = 0x0018 ); + private: + Box * Container; + + void SetReserved( ); + void SetDefaults( ); +};//Box_ftyp Class + +Box_avcC::Box_avcC( ) { + Container = new Box( 0x61766343 ); + SetReserved(); + SetDefaults(); +} + +Box_avcC::~Box_avcC() { + delete Container; +} + +Box * Box_avcC::GetBox() { + return Container; +} + +void Box_avcC::SetDataReferenceIndex( uint16_t DataReferenceIndex ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( DataReferenceIndex ),6); +} + +void Box_avcC::SetWidth( uint16_t Width ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( Width ),24); +} + +void Box_avcC::SetHeight( uint16_t Height ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( Height ),26); +} + +void Box_avcC::SetResolution ( uint32_t Horizontal, uint32_t Vertical ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8( Vertical ),32); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8( Horizontal ),28); +} + +void Box_avcC::SetFrameCount ( uint16_t FrameCount ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( FrameCount ),40); +} + +void Box_avcC::SetCompressorName ( std::string CompressorName ) { + uint8_t * Printable = new uint8_t[1]; + Printable[0] = std::min( (unsigned int)31, CompressorName.size() ); + Container->SetPayload((uint32_t)Printable[0],(uint8_t*)CompressorName.c_str(),43); + Container->SetPayload((uint32_t)1, Printable ,42); +} + +void Box_avcC::SetDepth ( uint16_t Depth ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( Depth ),74); +} + +void Box_avcC::SetReserved( ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( (uint16_t)-1 ),76); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),36); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),20); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),16); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),12); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),8); + Container->SetPayload((uint32_t)4,Box::uint16_to_uint8(0),4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_avcC::SetDefaults( ) { + SetWidth( ); + SetHeight( ); + SetDepth ( ); + SetFrameCount ( ); + SetResolution ( ); +} diff --git a/util/MP4/box_dinf.cpp b/util/MP4/box_dinf.cpp new file mode 100644 index 00000000..d8d4d243 --- /dev/null +++ b/util/MP4/box_dinf.cpp @@ -0,0 +1,43 @@ +#include "box.cpp" +#include +#include + +class Box_dinf { + public: + Box_dinf(); + ~Box_dinf(); + Box * GetBox(); + void AddContent( Box * newcontent ); + void WriteContent( ); + private: + Box * Container; + + Box * Content; +};//Box_ftyp Class + +Box_dinf::Box_dinf( ) { + Container = new Box( 0x64696E66 ); +} + +Box_dinf::~Box_dinf() { + delete Container; +} + +Box * Box_dinf::GetBox() { + return Container; +} + +void Box_dinf::AddContent( Box * newcontent ) { + if(Content) { + delete Content; + Content = NULL; + } + Content = newcontent; +} + +void Box_dinf::WriteContent( ) { + Container->ResetPayload( ); + std::string serializedbox = ""; + serializedbox.append((char*)Content->GetBoxedData(),Content->GetBoxedDataSize()); + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str()); +} diff --git a/util/MP4/box_dref.cpp b/util/MP4/box_dref.cpp new file mode 100644 index 00000000..cc6a2f5a --- /dev/null +++ b/util/MP4/box_dref.cpp @@ -0,0 +1,58 @@ +#include "box.cpp" +#include +#include + +class Box_dref { + public: + Box_dref(); + ~Box_dref(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + void SetReserved( ); + std::vector Content; +};//Box_ftyp Class + +Box_dref::Box_dref( ) { + Container = new Box( 0x64726566 ); + SetReserved( ); +} + +Box_dref::~Box_dref() { + delete Container; +} + +Box * Box_dref::GetBox() { + return Container; +} + +void Box_dref::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_dref::WriteContent( ) { + Container->ResetPayload( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str(),4); + SetReserved( ); +} + +void Box_dref::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} diff --git a/util/MP4/box_esds.cpp b/util/MP4/box_esds.cpp new file mode 100644 index 00000000..7253f07d --- /dev/null +++ b/util/MP4/box_esds.cpp @@ -0,0 +1,55 @@ +#include "box.cpp" +#include + +class Box_esds { + public: + Box_esds( ); + ~Box_esds(); + Box * GetBox(); + void SetDataReferenceIndex( uint16_t DataReferenceIndex = 1); + void SetChannelCount( uint16_t Count = 2 ); + void SetSampleSize( uint16_t Size = 16 ); + private: + Box * Container; + + void SetReserved( ); + void SetDefaults( ); +};//Box_ftyp Class + +Box_esds::Box_esds( ) { + Container = new Box( 0x65736473 ); + SetReserved(); + SetDefaults(); +} + +Box_esds::~Box_esds() { + delete Container; +} + +Box * Box_esds::GetBox() { + return Container; +} + +void Box_esds::SetDataReferenceIndex( uint16_t DataReferenceIndex ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( DataReferenceIndex ),6); +} + +void Box_esds::SetChannelCount( uint16_t Count ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( Count ),16); +} + +void Box_esds::SetSampleSize( uint16_t Size ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( Size ),18); +} + +void Box_esds::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8( 0 ),20); + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8( 0 ),4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8( 0 )); +} + +void Box_esds::SetDefaults( ) { + SetSampleSize( ); + SetChannelCount( ); + SetDataReferenceIndex( ); +} diff --git a/util/MP4/box_ftyp.cpp b/util/MP4/box_ftyp.cpp new file mode 100644 index 00000000..97ba9c3a --- /dev/null +++ b/util/MP4/box_ftyp.cpp @@ -0,0 +1,39 @@ +#include "box.cpp" + +class Box_ftyp { + public: + Box_ftyp( ); + ~Box_ftyp(); + Box * GetBox(); + void SetMajorBrand( uint32_t MajorBrand = 0x66347620 ); + void SetMinorBrand( uint32_t MinorBrand = 0x1 ); + private: + void SetDefaults( ); + Box * Container; +};//Box_ftyp Class + +Box_ftyp::Box_ftyp( ) { + Container = new Box( 0x66747970 ); + SetDefaults( ); +} + +Box_ftyp::~Box_ftyp() { + delete Container; +} + +Box * Box_ftyp::GetBox() { + return Container; +} + +void Box_ftyp::SetMajorBrand( uint32_t MajorBrand ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(MajorBrand)); +} + +void Box_ftyp::SetMinorBrand( uint32_t MinorBrand ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(MinorBrand),4); +} + +void Box_ftyp::SetDefaults( ) { + SetMinorBrand( ); + SetMajorBrand( ); +} diff --git a/util/MP4/box_hdlr.cpp b/util/MP4/box_hdlr.cpp new file mode 100644 index 00000000..5926740c --- /dev/null +++ b/util/MP4/box_hdlr.cpp @@ -0,0 +1,59 @@ +#include "box.cpp" +#include + +class Box_hdlr { + public: + Box_hdlr( ); + ~Box_hdlr(); + Box * GetBox(); + void SetHandlerType( uint32_t HandlerType = 0 ); + void SetName ( std::string Name = "" ); + private: + Box * Container; + void SetReserved( ); + void SetDefaults( ); + uint32_t CurrentHandlerType; +};//Box_ftyp Class + +Box_hdlr::Box_hdlr( ) { + Container = new Box( 0x68646C72 ); + CurrentHandlerType = 0; + SetReserved(); +} + +Box_hdlr::~Box_hdlr() { + delete Container; +} + +Box * Box_hdlr::GetBox() { + return Container; +} + +void Box_hdlr::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),20); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),16); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),12); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_hdlr::SetHandlerType( uint32_t HandlerType ) { + if( HandlerType != 0 ) { + CurrentHandlerType = HandlerType; + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(CurrentHandlerType),8); +} + +void Box_hdlr::SetName ( std::string Name ) { + char * tmp = new char[Name.size()+1]; + strcpy(tmp,Name.c_str()); + Container->ResetPayload(); + SetReserved(); + SetHandlerType(0); + Container->SetPayload((uint32_t)strlen(tmp)+1,(uint8_t*)tmp,24); +} + +void Box_hdlr::SetDefaults( ) { + SetName( ); + SetHandlerType( ); +} diff --git a/util/MP4/box_hmhd.cpp b/util/MP4/box_hmhd.cpp new file mode 100644 index 00000000..8733b822 --- /dev/null +++ b/util/MP4/box_hmhd.cpp @@ -0,0 +1,57 @@ +#include "box.cpp" + +class Box_hmhd { + public: + Box_hmhd( ); + ~Box_hmhd(); + Box * GetBox(); + void SetMaxPDUSize( uint16_t Size = 0 ); + void SetAvgPDUSize( uint16_t Size = 0 ); + void SetMaxBitRate( uint32_t Rate = 0 ); + void SetAvgBitRate( uint32_t Rate = 0 ); + private: + Box * Container; + void SetReserved( ); + void SetDefaults( ); +};//Box_ftyp Class + +Box_hmhd::Box_hmhd( ) { + Container = new Box( 0x686D6864 ); + SetDefaults(); + SetReserved(); +} + +Box_hmhd::~Box_hmhd() { + delete Container; +} + +Box * Box_hmhd::GetBox() { + return Container; +} + +void Box_hmhd::SetMaxPDUSize( uint16_t Size ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(Size),4); +} + +void Box_hmhd::SetAvgPDUSize( uint16_t Size ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(Size),6); +} + +void Box_hmhd::SetMaxBitRate( uint32_t Rate ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Rate),8); +} + +void Box_hmhd::SetAvgBitRate( uint32_t Rate ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Rate),12); +} + +void Box_hmhd::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),16); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} +void Box_hmhd::SetDefaults( ) { + SetAvgBitRate( ); + SetMaxBitRate( ); + SetAvgPDUSize( ); + SetMaxPDUSize( ); +} diff --git a/util/MP4/box_includes.h b/util/MP4/box_includes.h new file mode 100644 index 00000000..2b796702 --- /dev/null +++ b/util/MP4/box_includes.h @@ -0,0 +1,37 @@ +#include "box_abst.cpp" +#include "box_afra.cpp" +#include "box_afrt.cpp" +#include "box_amhp.cpp" +#include "box_asrt.cpp" +#include "box_avcC.cpp" +#include "box_dinf.cpp" +#include "box_dref.cpp" +#include "box_esds.cpp" +#include "box_ftyp.cpp" +#include "box_hdlr.cpp" +#include "box_hmhd.cpp" +#include "box_mdat.cpp" +#include "box_mdhd.cpp" +#include "box_mdia.cpp" +#include "box_mfhd.cpp" +#include "box_minf.cpp" +#include "box_moof.cpp" +#include "box_moov.cpp" +#include "box_mvex.cpp" +#include "box_mvhd.cpp" +#include "box_nmhd.cpp" +#include "box_rtmp.cpp" +#include "box_smhd.cpp" +#include "box_stbl.cpp" +#include "box_stco.cpp" +#include "box_stsc.cpp" +#include "box_stsd.cpp" +#include "box_stts.cpp" +#include "box_tfhd.cpp" +#include "box_tkhd.cpp" +#include "box_traf.cpp" +#include "box_trak.cpp" +#include "box_trex.cpp" +#include "box_trun.cpp" +#include "box_url.cpp" +#include "box_vmhd.cpp" diff --git a/util/MP4/box_mdat.cpp b/util/MP4/box_mdat.cpp new file mode 100644 index 00000000..258585aa --- /dev/null +++ b/util/MP4/box_mdat.cpp @@ -0,0 +1,29 @@ +#include "box.cpp" +#include +#include + +class Box_mdat { + public: + Box_mdat(); + ~Box_mdat(); + Box * GetBox(); + void SetContent( uint8_t * NewData, uint32_t DataLength , uint32_t offset = 0 ); + private: + Box * Container; +};//Box_ftyp Class + +Box_mdat::Box_mdat( ) { + Container = new Box( 0x6D646174 ); +} + +Box_mdat::~Box_mdat() { + delete Container; +} + +Box * Box_mdat::GetBox() { + return Container; +} + +void Box_mdat::SetContent( uint8_t * NewData, uint32_t DataLength , uint32_t Offset ) { + Container->SetPayload(DataLength,NewData,Offset); +} diff --git a/util/MP4/box_mdhd.cpp b/util/MP4/box_mdhd.cpp new file mode 100644 index 00000000..ed143270 --- /dev/null +++ b/util/MP4/box_mdhd.cpp @@ -0,0 +1,88 @@ +#include "box.cpp" +#include + +#define SECONDS_DIFFERENCE 2082844800 + +class Box_mdhd { + public: + Box_mdhd( ); + ~Box_mdhd(); + Box * GetBox(); + void SetCreationTime( uint32_t TimeStamp = 0 ); + void SetModificationTime( uint32_t TimeStamp = 0 ); + void SetTimeScale( uint32_t TimeUnits = 0 ); + void SetDurationTime( uint32_t TimeUnits = 0 ); + void SetLanguage( uint8_t Firstchar = 'n', uint8_t Secondchar = 'l', uint8_t Thirdchar = 'd' ); + private: + void SetReserved(); + void SetDefaults(); + Box * Container; +};//Box_ftyp Class + +Box_mdhd::Box_mdhd( ) { + Container = new Box( 0x6D646864 ); +} + +Box_mdhd::~Box_mdhd() { + delete Container; +} + +Box * Box_mdhd::GetBox() { + return Container; +} + +void Box_mdhd::SetCreationTime( uint32_t TimeStamp ) { + uint32_t CreationTime; + if(!TimeStamp) { + CreationTime = time(NULL) + SECONDS_DIFFERENCE; + } else { + CreationTime = TimeStamp; + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(CreationTime),4); +} + +void Box_mdhd::SetModificationTime( uint32_t TimeStamp ) { + uint32_t ModificationTime; + if(!TimeStamp) { + ModificationTime = time(NULL) + SECONDS_DIFFERENCE; + } else { + ModificationTime = TimeStamp; + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(ModificationTime),8); +} + +void Box_mdhd::SetTimeScale( uint32_t TimeUnits ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(TimeUnits),12); +} + +void Box_mdhd::SetDurationTime( uint32_t TimeUnits ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(TimeUnits),16); +} + +void Box_mdhd::SetLanguage( uint8_t Firstchar, uint8_t Secondchar, uint8_t Thirdchar ) { + uint8_t FirstByte = 0; + uint8_t SecondByte = 0; + Firstchar -= 0x60; + Secondchar -= 0x60; + Thirdchar -= 0x60; + FirstByte += (Firstchar << 2); + FirstByte += (Secondchar >> 3); + SecondByte += (Secondchar << 5); + SecondByte += Thirdchar; + + Container->SetPayload((uint32_t)1,&SecondByte,21); + Container->SetPayload((uint32_t)1,&FirstByte,20); +} + +void Box_mdhd::SetReserved() { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(0),22); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_mdhd::SetDefaults() { + SetLanguage(); + SetDurationTime(); + SetTimeScale(); + SetModificationTime(); + SetCreationTime(); +} diff --git a/util/MP4/box_mdia.cpp b/util/MP4/box_mdia.cpp new file mode 100644 index 00000000..553137a7 --- /dev/null +++ b/util/MP4/box_mdia.cpp @@ -0,0 +1,51 @@ +#include "box.cpp" +#include +#include + +class Box_mdia { + public: + Box_mdia(); + ~Box_mdia(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Content; +};//Box_ftyp Class + +Box_mdia::Box_mdia( ) { + Container = new Box( 0x6D646961 ); +} + +Box_mdia::~Box_mdia() { + delete Container; +} + +Box * Box_mdia::GetBox() { + return Container; +} + +void Box_mdia::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_mdia::WriteContent( ) { + Container->ResetPayload( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str()); +} diff --git a/util/MP4/box_mfhd.cpp b/util/MP4/box_mfhd.cpp new file mode 100644 index 00000000..2680ab0a --- /dev/null +++ b/util/MP4/box_mfhd.cpp @@ -0,0 +1,39 @@ +#include "box.cpp" + +class Box_mfhd { + public: + Box_mfhd( ); + ~Box_mfhd(); + Box * GetBox(); + void SetSequenceNumber( uint32_t SequenceNumber = 1 ); + private: + void SetDefaults( ); + void SetReserved( ); + Box * Container; +};//Box_ftyp Class + +Box_mfhd::Box_mfhd( ) { + Container = new Box( 0x6D666864 ); + SetDefaults( ); + SetReserved( ); +} + +Box_mfhd::~Box_mfhd() { + delete Container; +} + +Box * Box_mfhd::GetBox() { + return Container; +} + +void Box_mfhd::SetDefaults( ) { + SetSequenceNumber( ); +} + +void Box_mfhd::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_mfhd::SetSequenceNumber( uint32_t SequenceNumber ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(SequenceNumber),4); +} diff --git a/util/MP4/box_minf.cpp b/util/MP4/box_minf.cpp new file mode 100644 index 00000000..ebde6c56 --- /dev/null +++ b/util/MP4/box_minf.cpp @@ -0,0 +1,51 @@ +#include "box.cpp" +#include +#include + +class Box_minf { + public: + Box_minf(); + ~Box_minf(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Content; +};//Box_ftyp Class + +Box_minf::Box_minf( ) { + Container = new Box( 0x6D696E66 ); +} + +Box_minf::~Box_minf() { + delete Container; +} + +Box * Box_minf::GetBox() { + return Container; +} + +void Box_minf::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_minf::WriteContent( ) { + Container->ResetPayload( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str()); +} diff --git a/util/MP4/box_moof.cpp b/util/MP4/box_moof.cpp new file mode 100644 index 00000000..1b18a9e5 --- /dev/null +++ b/util/MP4/box_moof.cpp @@ -0,0 +1,51 @@ +#include "box.cpp" +#include +#include + +class Box_moof { + public: + Box_moof(); + ~Box_moof(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Content; +};//Box_ftyp Class + +Box_moof::Box_moof( ) { + Container = new Box( 0x6D6F6F66 ); +} + +Box_moof::~Box_moof() { + delete Container; +} + +Box * Box_moof::GetBox() { + return Container; +} + +void Box_moof::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_moof::WriteContent( ) { + Container->ResetPayload( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str()); +} diff --git a/util/MP4/box_moov.cpp b/util/MP4/box_moov.cpp new file mode 100644 index 00000000..84542977 --- /dev/null +++ b/util/MP4/box_moov.cpp @@ -0,0 +1,51 @@ +#include "box.cpp" +#include +#include + +class Box_moov { + public: + Box_moov(); + ~Box_moov(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Content; +};//Box_ftyp Class + +Box_moov::Box_moov( ) { + Container = new Box( 0x6D6F6F76 ); +} + +Box_moov::~Box_moov() { + delete Container; +} + +Box * Box_moov::GetBox() { + return Container; +} + +void Box_moov::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_moov::WriteContent( ) { + Container->ResetPayload( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str()); +} diff --git a/util/MP4/box_mvex.cpp b/util/MP4/box_mvex.cpp new file mode 100644 index 00000000..8d6725ac --- /dev/null +++ b/util/MP4/box_mvex.cpp @@ -0,0 +1,51 @@ +#include "box.cpp" +#include +#include + +class Box_mvex { + public: + Box_mvex(); + ~Box_mvex(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Content; +};//Box_ftyp Class + +Box_mvex::Box_mvex( ) { + Container = new Box( 0x6D866578 ); +} + +Box_mvex::~Box_mvex() { + delete Container; +} + +Box * Box_mvex::GetBox() { + return Container; +} + +void Box_mvex::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_mvex::WriteContent( ) { + Container->ResetPayload( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str()); +} diff --git a/util/MP4/box_mvhd.cpp b/util/MP4/box_mvhd.cpp new file mode 100644 index 00000000..8055abe5 --- /dev/null +++ b/util/MP4/box_mvhd.cpp @@ -0,0 +1,113 @@ +#include "box.cpp" +#include + +#define SECONDS_DIFFERENCE 2082844800 + +class Box_mvhd { + public: + Box_mvhd( ); + ~Box_mvhd(); + Box * GetBox(); + void SetCreationTime( uint32_t TimeStamp = 0 ); + void SetModificationTime( uint32_t TimeStamp = 0 ); + void SetTimeScale( uint32_t TimeUnits = 1 ); + void SetDurationTime( uint32_t TimeUnits = 0 ); + void SetRate( uint32_t Rate = 0x00010000 ); + void SetVolume( uint16_t Volume = 0x0100 ); + void SetNextTrackID( uint32_t TrackID = 0xFFFFFFFF ); + private: + void SetReserved(); + void SetDefaults(); + Box * Container; + +};//Box_ftyp Class + +Box_mvhd::Box_mvhd( ) { + Container = new Box( 0x6D766864 ); + SetDefaults(); + SetReserved(); +} + +Box_mvhd::~Box_mvhd() { + delete Container; +} + +Box * Box_mvhd::GetBox() { + return Container; +} + +void Box_mvhd::SetCreationTime( uint32_t TimeStamp ) { + uint32_t CreationTime; + if(!TimeStamp) { + CreationTime = time(NULL) + SECONDS_DIFFERENCE; + } else { + CreationTime = TimeStamp; + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(CreationTime),4); +} + +void Box_mvhd::SetModificationTime( uint32_t TimeStamp ) { + uint32_t ModificationTime; + if(!TimeStamp) { + ModificationTime = time(NULL) + SECONDS_DIFFERENCE; + } else { + ModificationTime = TimeStamp; + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(ModificationTime),8); +} + +void Box_mvhd::SetTimeScale( uint32_t TimeUnits ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(TimeUnits),12); +} + +void Box_mvhd::SetDurationTime( uint32_t TimeUnits ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(TimeUnits),16); +} + +void Box_mvhd::SetRate( uint32_t Rate ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Rate),20); +} + +void Box_mvhd::SetVolume( uint16_t Volume ) { + Container->SetPayload((uint32_t)4,Box::uint16_to_uint8(Volume),24); +} + +void Box_mvhd::SetNextTrackID( uint32_t TrackID ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(TrackID),92); +} + +void Box_mvhd::SetReserved() { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),88); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),84); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),80); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),76); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),72); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),68); + + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0x40000000),64); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),60); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),56); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),52); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0x00010000),48); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),44); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),40); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),36); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0x00010000),32); + + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),28); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),24); + Container->SetPayload((uint32_t)4,Box::uint16_to_uint8(0),22); + + Container->SetPayload((uint32_t)4,Box::uint16_to_uint8(0)); +} + +void Box_mvhd::SetDefaults() { + SetCreationTime(); + SetModificationTime(); + SetDurationTime(); + SetNextTrackID(); + SetRate(); + SetVolume(); + SetTimeScale(); +} + diff --git a/util/MP4/box_nmhd.cpp b/util/MP4/box_nmhd.cpp new file mode 100644 index 00000000..d874d1ed --- /dev/null +++ b/util/MP4/box_nmhd.cpp @@ -0,0 +1,28 @@ +#include "box.cpp" + +class Box_nmhd { + public: + Box_nmhd( ); + ~Box_nmhd(); + Box * GetBox(); + private: + Box * Container; + void SetReserved( ); +};//Box_ftyp Class + +Box_nmhd::Box_nmhd( ) { + Container = new Box( 0x6E6D6864 ); + SetReserved(); +} + +Box_nmhd::~Box_nmhd() { + delete Container; +} + +Box * Box_nmhd::GetBox() { + return Container; +} + +void Box_nmhd::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} diff --git a/util/MP4/box_rtmp.cpp b/util/MP4/box_rtmp.cpp new file mode 100644 index 00000000..980c7ef3 --- /dev/null +++ b/util/MP4/box_rtmp.cpp @@ -0,0 +1,89 @@ +#include "box.cpp" +#include + +class Box_rtmp { + public: + Box_rtmp( ); + ~Box_rtmp(); + Box * GetBox(); + void SetDataReferenceIndex( uint16_t NewIndex = 0 ); + void SetHintTrackVersion( uint16_t NewVersion = 1 ); + void SetHighestCompatibleVersion( uint16_t NewVersion = 1 ); + void SetMaxPacketSize( uint16_t NewSize = 0xFFFF ); + void AddContent( Box * newcontent ); + void WriteContent( ); + private: + void SetReserved( ); + void SetDefaults( ); + uint16_t CurrentReferenceIndex; + uint16_t CurrentHintTrackVersion; + uint16_t CurrentHighestCompatibleVersion; + uint16_t CurrentMaxPacketSize; + + Box * Container; + Box * Content; +};//Box_ftyp Class + +Box_rtmp::Box_rtmp( ) { + Container = new Box( 0x72746D70 ); + SetReserved(); + SetDefaults(); +} + +Box_rtmp::~Box_rtmp() { + delete Container; +} + +Box * Box_rtmp::GetBox() { + return Container; +} + +void Box_rtmp::SetReserved( ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(CurrentMaxPacketSize),12); + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(CurrentHighestCompatibleVersion),10); + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(CurrentHintTrackVersion),8); + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(CurrentReferenceIndex),6); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),2); + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(0)); +} + +void Box_rtmp::SetDefaults( ) { + SetDataReferenceIndex( ); + SetHintTrackVersion( ); + SetHighestCompatibleVersion( ); + SetMaxPacketSize( ); +} + +void Box_rtmp::SetDataReferenceIndex( uint16_t NewIndex ) { + CurrentReferenceIndex = NewIndex; + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(NewIndex),6); +} +void Box_rtmp::SetHintTrackVersion( uint16_t NewVersion ) { + CurrentHintTrackVersion = NewVersion; + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(NewVersion),8); +} +void Box_rtmp::SetHighestCompatibleVersion( uint16_t NewVersion ) { + CurrentHighestCompatibleVersion = NewVersion; + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(NewVersion),10); +} + +void Box_rtmp::SetMaxPacketSize( uint16_t NewSize ) { + CurrentMaxPacketSize = NewSize; + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(NewSize),12); +} + +void Box_rtmp::AddContent( Box * newcontent ) { + if(Content) { + delete Content; + Content = NULL; + } + Content = newcontent; +} + +void Box_rtmp::WriteContent( ) { + Container->ResetPayload( ); + SetReserved( ); + std::string serializedbox = ""; + serializedbox.append((char*)Content->GetBoxedData(),Content->GetBoxedDataSize()); + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str(),14); +} diff --git a/util/MP4/box_smhd.cpp b/util/MP4/box_smhd.cpp new file mode 100644 index 00000000..6b6f9d9f --- /dev/null +++ b/util/MP4/box_smhd.cpp @@ -0,0 +1,29 @@ +#include "box.cpp" + +class Box_smhd { + public: + Box_smhd( ); + ~Box_smhd(); + Box * GetBox(); + private: + Box * Container; + void SetReserved( ); +};//Box_ftyp Class + +Box_smhd::Box_smhd( ) { + Container = new Box( 0x736D6864 ); + SetReserved(); +} + +Box_smhd::~Box_smhd() { + delete Container; +} + +Box * Box_smhd::GetBox() { + return Container; +} + +void Box_smhd::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} diff --git a/util/MP4/box_stbl.cpp b/util/MP4/box_stbl.cpp new file mode 100644 index 00000000..44a8d129 --- /dev/null +++ b/util/MP4/box_stbl.cpp @@ -0,0 +1,51 @@ +#include "box.cpp" +#include +#include + +class Box_stbl { + public: + Box_stbl(); + ~Box_stbl(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Content; +};//Box_ftyp Class + +Box_stbl::Box_stbl( ) { + Container = new Box( 0x7374626C ); +} + +Box_stbl::~Box_stbl() { + delete Container; +} + +Box * Box_stbl::GetBox() { + return Container; +} + +void Box_stbl::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_stbl::WriteContent( ) { + Container->ResetPayload( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str()); +} diff --git a/util/MP4/box_stco.cpp b/util/MP4/box_stco.cpp new file mode 100644 index 00000000..434cede8 --- /dev/null +++ b/util/MP4/box_stco.cpp @@ -0,0 +1,58 @@ +#include "box.cpp" +#include +#include + +class Box_stco { + public: + Box_stco( ); + ~Box_stco(); + Box * GetBox(); + void AddOffset( uint32_t DataOffset, uint32_t Offset = 0 ); + void SetOffsets( std::vector NewOffsets ); + void WriteContent( ); + private: + Box * Container; + + void SetReserved( ); + std::vector Offsets; +};//Box_ftyp Class + +Box_stco::Box_stco( ) { + Container = new Box( 0x7374636F ); + SetReserved(); +} + +Box_stco::~Box_stco() { + delete Container; +} + +Box * Box_stco::GetBox() { + return Container; +} + +void Box_stco::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_stco::AddOffset( uint32_t DataOffset, uint32_t Offset ) { + if(Offset >= Offsets.size()) { + Offsets.resize(Offset+1); + } + Offsets[Offset] = DataOffset; +} + + +void Box_stco::WriteContent( ) { + Container->ResetPayload(); + SetReserved( ); + if(!Offsets.empty()) { + for(int32_t i = Offsets.size() -1; i >= 0; i--) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Offsets[i]),(i*4)+8); + } + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Offsets.size()),4); +} + +void Box_stco::SetOffsets( std::vector NewOffsets ) { + Offsets = NewOffsets; +} diff --git a/util/MP4/box_stsc.cpp b/util/MP4/box_stsc.cpp new file mode 100644 index 00000000..ea8edd33 --- /dev/null +++ b/util/MP4/box_stsc.cpp @@ -0,0 +1,63 @@ +#include "box.cpp" +#include +#include + +struct stsc_record { + uint32_t FirstChunk; + uint32_t SamplesPerChunk; + uint32_t SampleDescIndex; +};//stsc_record + +class Box_stsc { + public: + Box_stsc( ); + ~Box_stsc(); + Box * GetBox(); + void SetReserved( ); + void AddEntry( uint32_t FirstChunk = 0, uint32_t SamplesPerChunk = 0, uint32_t SampleDescIndex = 0, uint32_t Offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Entries; +};//Box_ftyp Class + +Box_stsc::Box_stsc( ) { + Container = new Box( 0x73747363 ); + SetReserved(); +} + +Box_stsc::~Box_stsc() { + delete Container; +} + +Box * Box_stsc::GetBox() { + return Container; +} + +void Box_stsc::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_stsc::AddEntry( uint32_t FirstChunk, uint32_t SamplesPerChunk, uint32_t SampleDescIndex, uint32_t Offset ) { + if(Offset >= Entries.size()) { + Entries.resize(Offset+1); + } + Entries[Offset].FirstChunk = FirstChunk; + Entries[Offset].SamplesPerChunk = SamplesPerChunk; + Entries[Offset].SampleDescIndex = SampleDescIndex; +} + + +void Box_stsc::WriteContent( ) { + Container->ResetPayload(); + SetReserved( ); + if(!Entries.empty()) { + for(int32_t i = Entries.size() -1; i >= 0; i--) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].SampleDescIndex),(i*12)+16); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].SamplesPerChunk),(i*12)+12); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].FirstChunk),(i*12)+8); + } + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries.size()),4); +} diff --git a/util/MP4/box_stsd.cpp b/util/MP4/box_stsd.cpp new file mode 100644 index 00000000..233fa584 --- /dev/null +++ b/util/MP4/box_stsd.cpp @@ -0,0 +1,59 @@ +#include "box.cpp" +#include +#include + +class Box_stsd { + public: + Box_stsd( ); + ~Box_stsd(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent(); + private: + Box * Container; + + void SetReserved(); + std::vector Content; +};//Box_ftyp Class + +Box_stsd::Box_stsd( ) { + Container = new Box( 0x73747364 ); + SetReserved(); +} + +Box_stsd::~Box_stsd() { + delete Container; +} + +Box * Box_stsd::GetBox() { + return Container; +} + +void Box_stsd::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_stsd::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8( 1 ),4); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8( 0 ),0); +} + +void Box_stsd::WriteContent( ) { + Container->ResetPayload( ); + SetReserved( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str(),8); +} diff --git a/util/MP4/box_stts.cpp b/util/MP4/box_stts.cpp new file mode 100644 index 00000000..e16c42c0 --- /dev/null +++ b/util/MP4/box_stts.cpp @@ -0,0 +1,60 @@ +#include "box.cpp" +#include +#include + +struct stts_record { + uint32_t SampleCount; + uint32_t SampleDelta; +};//stsc_record + +class Box_stts { + public: + Box_stts( ); + ~Box_stts(); + Box * GetBox(); + void SetReserved( ); + void AddEntry( uint32_t SampleCount, uint32_t SampleDelta, uint32_t Offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Entries; +};//Box_ftyp Class + +Box_stts::Box_stts( ) { + Container = new Box( 0x73747473 ); + SetReserved(); +} + +Box_stts::~Box_stts() { + delete Container; +} + +Box * Box_stts::GetBox() { + return Container; +} + +void Box_stts::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_stts::AddEntry( uint32_t SampleCount, uint32_t SampleDelta, uint32_t Offset ) { + if(Offset >= Entries.size()) { + Entries.resize(Offset+1); + } + Entries[Offset].SampleCount = SampleCount; + Entries[Offset].SampleDelta = SampleDelta; +} + + +void Box_stts::WriteContent( ) { + Container->ResetPayload(); + SetReserved( ); + if(!Entries.empty()) { + for(int32_t i = Entries.size() -1; i >= 0; i--) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].SampleDelta),(i*8)+12); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries[i].SampleCount),(i*8)+8); + } + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Entries.size()),4); +} diff --git a/util/MP4/box_tfhd.cpp b/util/MP4/box_tfhd.cpp new file mode 100644 index 00000000..57ed10dc --- /dev/null +++ b/util/MP4/box_tfhd.cpp @@ -0,0 +1,88 @@ +#include "box.cpp" + +class Box_tfhd { + public: + Box_tfhd( ); + ~Box_tfhd(); + Box * GetBox(); + void SetTrackID( uint32_t TrackID = 0 ); + void SetBaseDataOffset( uint32_t Offset = 0 );//write as uint64_t + void SetSampleDescriptionIndex( uint32_t Index = 0 ); + void SetDefaultSampleDuration( uint32_t Duration = 0 ); + void SetDefaultSampleSize( uint32_t Size = 0 ); + void WriteContent( ); + private: + void SetDefaults( ); + uint32_t curTrackID; + uint32_t curBaseDataOffset; + uint32_t curSampleDescriptionIndex; + uint32_t curDefaultSampleDuration; + uint32_t curDefaultSampleSize; + Box * Container; +};//Box_ftyp Class + +Box_tfhd::Box_tfhd( ) { + Container = new Box( 0x74666864 ); + SetDefaults( ); +} + +Box_tfhd::~Box_tfhd() { + delete Container; +} + +Box * Box_tfhd::GetBox() { + return Container; +} + +void Box_tfhd::SetTrackID( uint32_t TrackID ) { + curTrackID = TrackID; +} + +void Box_tfhd::SetBaseDataOffset( uint32_t Offset ) { + curBaseDataOffset = Offset; +} + +void Box_tfhd::SetSampleDescriptionIndex( uint32_t Index ) { + curSampleDescriptionIndex = Index; +} + +void Box_tfhd::SetDefaultSampleDuration( uint32_t Duration ) { + curDefaultSampleDuration = Duration; +} + +void Box_tfhd::SetDefaultSampleSize( uint32_t Size ) { + curDefaultSampleSize = Size; +} + +void Box_tfhd::WriteContent( ) { + uint32_t curoffset; + uint32_t flags = 0 & ( curBaseDataOffset ? 0x1 : 0 ) & ( curSampleDescriptionIndex ? 0x2 : 0 ) & ( curDefaultSampleDuration ? 0x8 : 0 ) & ( curDefaultSampleSize ? 0x10 : 0 ); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(flags)); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curTrackID),4); + curoffset = 8; + if( curBaseDataOffset ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),curoffset); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curBaseDataOffset),curoffset+4); + curoffset += 8; + } + if( curSampleDescriptionIndex ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curSampleDescriptionIndex),curoffset); + curoffset += 8; + } + if( curDefaultSampleDuration ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curDefaultSampleDuration),curoffset); + curoffset += 8; + } + if( curDefaultSampleSize ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curDefaultSampleSize),curoffset); + curoffset += 8; + } +} + +void Box_tfhd::SetDefaults( ) { + SetTrackID( ); + SetBaseDataOffset( ); + SetSampleDescriptionIndex( ); + SetDefaultSampleDuration( ); + SetDefaultSampleSize( ); +} diff --git a/util/MP4/box_tkhd.cpp b/util/MP4/box_tkhd.cpp new file mode 100644 index 00000000..c8f5c1e7 --- /dev/null +++ b/util/MP4/box_tkhd.cpp @@ -0,0 +1,117 @@ +#include "box.cpp" +#include + +#define SECONDS_DIFFERENCE 2082844800 + +class Box_tkhd { + public: + Box_tkhd( ); + ~Box_tkhd(); + Box * GetBox(); + void SetCreationTime( uint32_t TimeStamp = 0 ); + void SetModificationTime( uint32_t TimeStamp = 0 ); + void SetDurationTime( uint32_t TimeUnits = 0 ); + void SetWidth( uint16_t Width = 0 ); + void SetHeight( uint16_t Height = 0 ); + void SetFlags( bool Bit0 = true, bool Bit1 = true, bool Bit2 = true ); + void SetVersion( uint32_t Version = 0 ); + void SetTrackID( uint32_t TrackID = 0 ); + private: + void SetReserved(); + void SetDefaults(); + Box * Container; + + uint32_t CurrentFlags; + uint32_t CurrentVersion; +};//Box_ftyp Class + +Box_tkhd::Box_tkhd( ) { + Container = new Box( 0x746B6864 ); + CurrentVersion = 0; + CurrentFlags = 0; +} + +Box_tkhd::~Box_tkhd() { + delete Container; +} + +Box * Box_tkhd::GetBox() { + return Container; +} + +void Box_tkhd::SetCreationTime( uint32_t TimeStamp ) { + uint32_t CreationTime; + if(!TimeStamp) { + CreationTime = time(NULL) + SECONDS_DIFFERENCE; + } else { + CreationTime = TimeStamp; + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(CreationTime),4); +} + +void Box_tkhd::SetModificationTime( uint32_t TimeStamp ) { + uint32_t ModificationTime; + if(!TimeStamp) { + ModificationTime = time(NULL) + SECONDS_DIFFERENCE; + } else { + ModificationTime = TimeStamp; + } + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(ModificationTime),8); +} + +void Box_tkhd::SetDurationTime( uint32_t TimeUnits ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(TimeUnits),16); +} + +void Box_tkhd::SetReserved() { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0x40000000),68); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),64); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),60); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),56); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0x10000),52); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),48); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),44); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),40); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0x10000),36); + Container->SetPayload((uint32_t)4,Box::uint16_to_uint8(0),34); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),28); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),24); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),20); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0),12); +} + +void Box_tkhd::SetVersion( uint32_t Version ) { + if ( Version >= 2 ) { return; } + CurrentVersion = Version; + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8((CurrentVersion<<24)&(CurrentFlags))); +} + +void Box_tkhd::SetFlags( bool Bit0, bool Bit1, bool Bit2 ) { + CurrentFlags = (( Bit0 ? 0x80 : 0 ) + ( Bit1 ? 0x40 : 0 ) + ( Bit2 ? 0x20 : 0 )) << 16 ; + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8((CurrentVersion<<24)&(CurrentFlags))); +} + +void Box_tkhd::SetTrackID( uint32_t TrackID ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(TrackID),12); +} + +void Box_tkhd::SetWidth( uint16_t Width ) { + uint32_t ResultWidth = ( Width << 16 ); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(ResultWidth),72); +} + +void Box_tkhd::SetHeight( uint16_t Height ) { + uint32_t ResultHeight = ( Height << 16 ); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(ResultHeight),76); +} + +void Box_tkhd::SetDefaults() { + SetHeight(); + SetWidth(); + SetCreationTime(); + SetModificationTime(); + SetDurationTime(); + SetFlags(); + SetVersion(); + SetTrackID(); +} diff --git a/util/MP4/box_traf.cpp b/util/MP4/box_traf.cpp new file mode 100644 index 00000000..fb794578 --- /dev/null +++ b/util/MP4/box_traf.cpp @@ -0,0 +1,51 @@ +#include "box.cpp" +#include +#include + +class Box_traf { + public: + Box_traf(); + ~Box_traf(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Content; +};//Box_ftyp Class + +Box_traf::Box_traf( ) { + Container = new Box( 0x74726166 ); +} + +Box_traf::~Box_traf() { + delete Container; +} + +Box * Box_traf::GetBox() { + return Container; +} + +void Box_traf::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_traf::WriteContent( ) { + Container->ResetPayload( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str()); +} diff --git a/util/MP4/box_trak.cpp b/util/MP4/box_trak.cpp new file mode 100644 index 00000000..b33bb5bd --- /dev/null +++ b/util/MP4/box_trak.cpp @@ -0,0 +1,51 @@ +#include "box.cpp" +#include +#include + +class Box_trak { + public: + Box_trak(); + ~Box_trak(); + Box * GetBox(); + void AddContent( Box * newcontent, uint32_t offset = 0 ); + void WriteContent( ); + private: + Box * Container; + + std::vector Content; +};//Box_ftyp Class + +Box_trak::Box_trak( ) { + Container = new Box( 0x7472616B ); +} + +Box_trak::~Box_trak() { + delete Container; +} + +Box * Box_trak::GetBox() { + return Container; +} + +void Box_trak::AddContent( Box * newcontent, uint32_t offset ) { + if( offset >= Content.size() ) { + Content.resize(offset+1); + } + if( Content[offset] ) { + delete Content[offset]; + } + Content[offset] = newcontent; +} + +void Box_trak::WriteContent( ) { + Container->ResetPayload( ); + Box * current; + std::string serializedbox = ""; + for( uint32_t i = 0; i < Content.size(); i++ ) { + current=Content[i]; + if( current ) { + serializedbox.append((char*)current->GetBoxedData(),current->GetBoxedDataSize()); + } + } + Container->SetPayload((uint32_t)serializedbox.size(),(uint8_t*)serializedbox.c_str()); +} diff --git a/util/MP4/box_trex.cpp b/util/MP4/box_trex.cpp new file mode 100644 index 00000000..16369795 --- /dev/null +++ b/util/MP4/box_trex.cpp @@ -0,0 +1,59 @@ +#include "box.cpp" + +class Box_trex { + public: + Box_trex( ); + ~Box_trex(); + Box * GetBox(); + void SetTrackID( uint32_t Id = 0 ); + void SetSampleDescriptionIndex( uint32_t Index = 0 ); + void SetSampleDuration( uint32_t Duration = 0 ); + void SetSampleSize( uint32_t Size = 0 ); + private: + void SetReserved( ); + void SetDefaults( ); + Box * Container; +};//Box_ftyp Class + +Box_trex::Box_trex( ) { + Container = new Box( 0x74726578 ); + SetReserved( ); + SetDefaults( ); +} + +Box_trex::~Box_trex() { + delete Container; +} + +Box * Box_trex::GetBox() { + return Container; +} + +void Box_trex::SetDefaults( ) { + SetTrackID( ); + SetSampleDescriptionIndex( ); + SetSampleDuration( ); + SetSampleSize( ); +} + +void Box_trex::SetReserved( ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(1),22); + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(0),20); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(0)); +} + +void Box_trex::SetTrackID( uint32_t Id ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Id),4); +} + +void Box_trex::SetSampleDescriptionIndex( uint32_t Index ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Index),8); +} + +void Box_trex::SetSampleDuration( uint32_t Duration ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Duration),12); +} + +void Box_trex::SetSampleSize( uint32_t Size ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(Size),16); +} diff --git a/util/MP4/box_trun.cpp b/util/MP4/box_trun.cpp new file mode 100644 index 00000000..1010f2da --- /dev/null +++ b/util/MP4/box_trun.cpp @@ -0,0 +1,68 @@ +#include "box.cpp" +#include + +struct trun_sampleinformationstructure { + uint32_t SampleDuration; + uint32_t SampleSize; +}; + +class Box_trun { + public: + Box_trun( ); + ~Box_trun(); + Box * GetBox(); + void SetDataOffset( uint32_t Offset = 0 ); + void AddSampleInformation( uint32_t SampleDuration = 0, uint32_t SampleSize = 0, uint32_t Offset = 0 ); + void WriteContent( ); + private: + void SetDefaults( ); + bool setSampleDuration; + bool setSampleSize; + uint32_t curDataOffset; + std::vector SampleInfo; + Box * Container; +};//Box_ftyp Class + +Box_trun::Box_trun( ) { + Container = new Box( 0x74666864 ); + SetDefaults( ); +} + +Box_trun::~Box_trun() { + delete Container; +} + +Box * Box_trun::GetBox() { + return Container; +} + +void Box_trun::SetDataOffset( uint32_t Offset ) { + curDataOffset = Offset; +} + +void Box_trun::WriteContent( ) { + uint32_t curoffset; + uint32_t flags = 0 & ( curDataOffset ? 0x1 : 0 ) & ( setSampleDuration ? 0x100 : 0 ) & ( setSampleSize ? 0x200 : 0 ); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(flags)); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(SampleInfo.size()),4); + curoffset = 8; + if( curDataOffset ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(curDataOffset),curoffset); + curoffset += 4; + } + for( uint32_t i = 0; i < SampleInfo.size(); i++ ) { + if( setSampleDuration ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(SampleInfo[i].SampleDuration),curoffset); + curoffset += 4; + } + if( setSampleSize ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(SampleInfo[i].SampleSize),curoffset); + curoffset += 4; + } + } +} + +void Box_trun::SetDefaults( ) { + setSampleDuration = false; + setSampleSize = false; +} diff --git a/util/MP4/box_url.cpp b/util/MP4/box_url.cpp new file mode 100644 index 00000000..8287f7c3 --- /dev/null +++ b/util/MP4/box_url.cpp @@ -0,0 +1,23 @@ +#include "box.cpp" + +class Box_url { + public: + Box_url( ); + ~Box_url(); + Box * GetBox(); + private: + Box * Container; +};//Box_ftyp Class + +Box_url::Box_url( ) { + Container = new Box( 0x75726C20 ); + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(1)); +} + +Box_url::~Box_url() { + delete Container; +} + +Box * Box_url::GetBox() { + return Container; +} diff --git a/util/MP4/box_vmhd.cpp b/util/MP4/box_vmhd.cpp new file mode 100644 index 00000000..6dd5fb8e --- /dev/null +++ b/util/MP4/box_vmhd.cpp @@ -0,0 +1,45 @@ +#include "box.cpp" + +class Box_vmhd { + public: + Box_vmhd( ); + ~Box_vmhd(); + Box * GetBox(); + void SetGraphicsMode( uint16_t GraphicsMode = 0 ); + void SetOpColor( uint16_t Red = 0, uint16_t Green = 0, uint16_t Blue = 0); + private: + Box * Container; + void SetReserved( ); + void SetDefaults( ); +};//Box_ftyp Class + +Box_vmhd::Box_vmhd( ) { + Container = new Box( 0x766D6864 ); + SetDefaults(); + SetReserved(); +} + +Box_vmhd::~Box_vmhd() { + delete Container; +} + +Box * Box_vmhd::GetBox() { + return Container; +} + +void Box_vmhd::SetGraphicsMode( uint16_t GraphicsMode ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(GraphicsMode),8); +} +void Box_vmhd::SetOpColor( uint16_t Red, uint16_t Green, uint16_t Blue ) { + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(Blue),14); + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(Green),12); + Container->SetPayload((uint32_t)2,Box::uint16_to_uint8(Red),10); +} + +void Box_vmhd::SetReserved( ) { + Container->SetPayload((uint32_t)4,Box::uint32_to_uint8(1)); +} +void Box_vmhd::SetDefaults( ) { + SetOpColor(); + SetGraphicsMode(); +} diff --git a/util/MP4/interface.cpp b/util/MP4/interface.cpp new file mode 100644 index 00000000..6e81a6d6 --- /dev/null +++ b/util/MP4/interface.cpp @@ -0,0 +1,583 @@ +#include "box_includes.h" + +#include + +class Interface { + public: + Interface(); + ~Interface(); + void link(); + uint32_t GetContentSize(); + uint8_t * GetContents(); + void SetWidth( uint16_t NewWidth ); + void SetHeight( uint16_t NewHeight ); + void SetDurationTime( uint32_t NewDuration, uint32_t Track ); + void SetTimeScale( uint32_t NewUnitsPerSecond, uint32_t Track ); + void AddSTTSEntry( uint32_t SampleCount, uint32_t SampleDelta, uint32_t Track ); + void EmptySTTS( uint32_t Track ); + void AddSTSCEntry( uint32_t FirstChunk, uint32_t SamplesPerChunk, uint32_t Track ); + void EmptySTSC( uint32_t Track ); + void SetOffsets( std::vector NewOffsets, uint32_t Track ); + void SetData( std::string data ); + std::string GenerateLiveBootstrap( uint32_t CurMediaTime ); + static std::string mdatFold(std::string data); + private: + void SetStaticDefaults(); + void UpdateContents(); + void WriteSTTS( uint32_t Track ); + void WriteSTSC( uint32_t Track ); + bool AllBoxesExist(); + uint16_t Width; + uint16_t Height; + std::vector Duration; + std::vector UnitsPerSecond; + std::vector sttsvide; + std::vector sttssoun; + std::vector stscvide; + std::vector stscsoun; + Box_ftyp * ftyp; + Box_moov * moov; + Box_mvhd * mvhd; + Box_trak * trak_vide; + Box_tkhd * tkhd_vide; + Box_mdia * mdia_vide; + Box_mdhd * mdhd_vide; + Box_hdlr * hdlr_vide; + Box_minf * minf_vide; + Box_vmhd * vmhd_vide; + Box_dinf * dinf_vide; + Box_dref * dref_vide; + Box_url * url_vide; + Box_stbl * stbl_vide; + Box_stts * stts_vide; + Box_stsc * stsc_vide; + Box_stco * stco_vide; + Box_stsd * stsd_vide; + Box_avcC * avcC_vide; + Box_trak * trak_soun; + Box_tkhd * tkhd_soun; + Box_mdia * mdia_soun; + Box_mdhd * mdhd_soun; + Box_hdlr * hdlr_soun; + Box_minf * minf_soun; + Box_smhd * smhd_soun; + Box_dinf * dinf_soun; + Box_dref * dref_soun; + Box_url * url_soun; + Box_stbl * stbl_soun; + Box_stts * stts_soun; + Box_stsc * stsc_soun; + Box_stco * stco_soun; + Box_stsd * stsd_soun; + Box_esds * esds_soun; + Box_rtmp * rtmp; + Box_amhp * amhp; + Box_mvex * mvex; + Box_trex * trex_vide; + Box_trex * trex_soun; + Box_afra * afra; + Box_abst * abst; + Box_asrt * asrt; + Box_afrt * afrt; + Box_moof * moof; + Box_mfhd * mfhd; + Box_traf * traf_vide; + Box_tfhd * tfhd_vide; + Box_trun * trun_vide; + Box_traf * traf_soun; + Box_tfhd * tfhd_soun; + Box_trun * trun_soun; +};//Interface class + +Interface::Interface() { + //Initializing local data + Width = 0; + Height = 0; + //Creating the boxes + ftyp = new Box_ftyp(); + moov = new Box_moov(); + mvhd = new Box_mvhd(); + trak_vide = new Box_trak(); + tkhd_vide = new Box_tkhd(); + mdia_vide = new Box_mdia(); + mdhd_vide = new Box_mdhd(); + hdlr_vide = new Box_hdlr(); + minf_vide = new Box_minf(); + vmhd_vide = new Box_vmhd(); + dinf_vide = new Box_dinf(); + dref_vide = new Box_dref(); + url_vide = new Box_url(); + stbl_vide = new Box_stbl(); + stts_vide = new Box_stts(); + stsc_vide = new Box_stsc(); + stco_vide = new Box_stco(); + stsd_vide = new Box_stsd(); + avcC_vide = new Box_avcC(); + trak_soun = new Box_trak(); + tkhd_soun = new Box_tkhd(); + mdia_soun = new Box_mdia(); + mdhd_soun = new Box_mdhd(); + hdlr_soun = new Box_hdlr(); + minf_soun = new Box_minf(); + smhd_soun = new Box_smhd(); + dinf_soun = new Box_dinf(); + dref_soun = new Box_dref(); + url_soun = new Box_url(); + stbl_soun = new Box_stbl(); + stts_soun = new Box_stts(); + stsc_soun = new Box_stsc(); + stco_soun = new Box_stco(); + stsd_soun = new Box_stsd(); + esds_soun = new Box_esds(); + rtmp = new Box_rtmp(); + amhp = new Box_amhp(); + mvex = new Box_mvex(); + trex_vide = new Box_trex(); + trex_soun = new Box_trex(); + afra = new Box_afra(); + abst = new Box_abst(); + asrt = new Box_asrt(); + afrt = new Box_afrt(); + moof = new Box_moof(); + mfhd = new Box_mfhd(); + traf_vide = new Box_traf(); + tfhd_vide = new Box_tfhd(); + trun_vide = new Box_trun(); + traf_soun = new Box_traf(); + tfhd_soun = new Box_tfhd(); + trun_soun = new Box_trun(); + //Set some values we already know won't change once the boxes have been created + SetStaticDefaults(); +} + +Interface::~Interface() { + //Deleting the boxes if they still exist. + if( trun_soun ) { delete trun_soun; trun_soun = NULL; } + if( tfhd_soun ) { delete tfhd_soun; tfhd_soun = NULL; } + if( traf_soun ) { delete traf_soun; traf_soun = NULL; } + if( trun_vide ) { delete trun_vide; trun_vide = NULL; } + if( tfhd_vide ) { delete tfhd_vide; tfhd_vide = NULL; } + if( traf_vide ) { delete traf_vide; traf_vide = NULL; } + if( mfhd ) { delete mfhd; mfhd = NULL; } + if( moof ) { delete moof; moof = NULL; } + if( afrt ) { delete afrt; afrt = NULL; } + if( asrt ) { delete asrt; asrt = NULL; } + if( abst ) { delete abst; abst = NULL; } + if( afra ) { delete afra; afra = NULL; } + if( trex_vide ) { delete trex_vide; trex_vide = NULL; } + if( trex_soun ) { delete trex_soun; trex_soun = NULL; } + if( mvex ) { delete mvex; mvex = NULL; } + if( amhp ) { delete amhp; amhp = NULL; } + if( rtmp ) { delete rtmp; rtmp = NULL; } + if( esds_soun ) { delete esds_soun; esds_soun = NULL; } + if( stsd_soun ) { delete stsd_soun; stsd_soun = NULL; } + if( stco_soun ) { delete stco_soun; stco_soun = NULL; } + if( stsc_soun ) { delete stsc_soun; stsc_soun = NULL; } + if( stts_soun ) { delete stts_soun; stts_soun = NULL; } + if( stbl_soun ) { delete stbl_soun; stbl_soun = NULL; } + if( url_soun ) { delete url_soun; url_soun = NULL; } + if( dref_soun ) { delete dref_soun; dref_soun = NULL; } + if( dinf_soun ) { delete dinf_soun; dinf_soun = NULL; } + if( minf_soun ) { delete minf_soun; minf_soun = NULL; } + if( hdlr_soun ) { delete hdlr_soun; hdlr_soun = NULL; } + if( mdhd_soun ) { delete mdhd_soun; mdhd_soun = NULL; } + if( mdia_soun ) { delete mdia_soun; mdia_soun = NULL; } + if( tkhd_soun ) { delete tkhd_soun; tkhd_soun = NULL; } + if( trak_soun ) { delete trak_soun; trak_soun = NULL; } + if( avcC_vide ) { delete avcC_vide; avcC_vide = NULL; } + if( stsd_vide ) { delete stsd_vide; stsd_vide = NULL; } + if( stco_vide ) { delete stco_vide; stco_vide = NULL; } + if( stsc_vide ) { delete stsc_vide; stsc_vide = NULL; } + if( stts_vide ) { delete stts_vide; stts_vide = NULL; } + if( stbl_vide ) { delete stbl_vide; stbl_vide = NULL; } + if( url_vide ) { delete url_vide; url_vide = NULL; } + if( dref_vide ) { delete dref_vide; dref_vide = NULL; } + if( dinf_vide ) { delete dinf_vide; dinf_vide = NULL; } + if( minf_vide ) { delete minf_vide; minf_vide = NULL; } + if( hdlr_vide ) { delete hdlr_vide; hdlr_vide = NULL; } + if( mdhd_vide ) { delete mdhd_vide; mdhd_vide = NULL; } + if( mdia_vide ) { delete mdia_vide; mdia_vide = NULL; } + if( tkhd_vide ) { delete tkhd_vide; tkhd_vide = NULL; } + if( trak_vide ) { delete trak_vide; trak_vide = NULL; } + if( mvhd ) { delete mvhd; mvhd = NULL; } + if( moov ) { delete moov; moov = NULL; } + if( ftyp ) { delete ftyp; ftyp = NULL; } +} + +void Interface::link( ) { + //Linking Video Track + stsd_vide->AddContent(avcC_vide->GetBox()); + stbl_vide->AddContent(stsd_vide->GetBox(),3); + stbl_vide->AddContent(stco_vide->GetBox(),2); + stbl_vide->AddContent(stsc_vide->GetBox(),1); + stbl_vide->AddContent(stts_vide->GetBox()); + dref_vide->AddContent(url_vide->GetBox()); + dinf_vide->AddContent(dref_vide->GetBox()); + minf_vide->AddContent(stbl_vide->GetBox(),2); + minf_vide->AddContent(dinf_vide->GetBox(),1); + minf_vide->AddContent(vmhd_vide->GetBox()); + mdia_vide->AddContent(minf_vide->GetBox(),2); + mdia_vide->AddContent(hdlr_vide->GetBox(),1); + mdia_vide->AddContent(mdhd_vide->GetBox()); + trak_vide->AddContent(mdia_vide->GetBox(),1); + trak_vide->AddContent(tkhd_vide->GetBox()); + + //Linking Sound Track + stsd_soun->AddContent(esds_soun->GetBox()); + stbl_soun->AddContent(stsd_soun->GetBox(),3); + stbl_soun->AddContent(stco_soun->GetBox(),2); + stbl_soun->AddContent(stsc_soun->GetBox(),1); + stbl_soun->AddContent(stts_soun->GetBox()); + dref_soun->AddContent(url_soun->GetBox()); + dinf_soun->AddContent(dref_soun->GetBox()); + minf_soun->AddContent(stbl_soun->GetBox(),2); + minf_soun->AddContent(dinf_soun->GetBox(),1); + minf_soun->AddContent(smhd_soun->GetBox()); + mdia_soun->AddContent(minf_soun->GetBox(),2); + mdia_soun->AddContent(hdlr_soun->GetBox(),1); + mdia_soun->AddContent(mdhd_soun->GetBox()); + trak_soun->AddContent(mdia_soun->GetBox(),1); + trak_soun->AddContent(tkhd_soun->GetBox()); + + //Linking mvex + mvex->AddContent(trex_soun->GetBox(),2); + mvex->AddContent(trex_vide->GetBox(),1); + + //Linking total file + moov->AddContent(mvex->GetBox(),3); + moov->AddContent(trak_soun->GetBox(),2); + moov->AddContent(trak_vide->GetBox(),1); + moov->AddContent(mvhd->GetBox()); + + rtmp->AddContent(amhp->GetBox()); + + //Linking ABST + abst->AddFragmentRunTable(afrt->GetBox()); + abst->AddSegmentRunTable(asrt->GetBox()); + + //Linking TRAF_SOUN + traf_soun->AddContent( trun_soun->GetBox(),1); + traf_soun->AddContent( tfhd_soun->GetBox() ); + + //Linking TRAF_vide + traf_vide->AddContent( trun_vide->GetBox(),1); + traf_vide->AddContent( tfhd_vide->GetBox() ); + + //Linking MOOF + moof->AddContent(traf_soun->GetBox(),2); + moof->AddContent(traf_vide->GetBox(),1); + moof->AddContent(mfhd->GetBox()); +} + +uint32_t Interface::GetContentSize( ) { + return ftyp->GetBox( )->GetBoxedDataSize( ) + moov->GetBox( )->GetBoxedDataSize( ) + rtmp->GetBox( )->GetBoxedDataSize( ); +} + +uint8_t * Interface::GetContents( ) { + uint8_t * Result = new uint8_t[GetContentSize( )]; + uint32_t Ftyp_Size = ftyp->GetBox( )->GetBoxedDataSize( ); + uint32_t Moov_Size = moov->GetBox( )->GetBoxedDataSize( ); + uint32_t Rtmp_Size = rtmp->GetBox( )->GetBoxedDataSize( ); + memcpy(Result,ftyp->GetBox( )->GetBoxedData( ),Ftyp_Size); + memcpy(&Result[Ftyp_Size],moov->GetBox( )->GetBoxedData( ),Moov_Size); + memcpy(&Result[Ftyp_Size+Moov_Size],rtmp->GetBox( )->GetBoxedData( ),Rtmp_Size); + return Result; +} + +void Interface::UpdateContents( ) { + if( !Width ) { fprintf(stderr,"WARNING: Width not set!\n"); } + if( !Height ) { fprintf(stderr,"WARNING: Height not set!\n"); } + if( !Duration.size() ) { fprintf(stderr,"WARNING: Duration not set!\n"); } + if( !UnitsPerSecond.size() ) { fprintf(stderr,"WARNING: Timescale not set!\n"); } + if( sttsvide.size() == 0 ) { + fprintf(stderr,"WARNING: No video stts available!\n"); + } else { WriteSTTS( 1 ); } + if( sttssoun.size() == 0 ) { + fprintf(stderr,"WARNING: No sound stts available!\n"); + } else { WriteSTTS( 2 ); } + if( stscvide.size() == 0 ) { + fprintf(stderr,"WARNING: No video stsc available!\n"); + } else { WriteSTSC( 1 ); } + if( stscsoun.size() == 0 ) { + fprintf(stderr,"WARNING: No sound stsc available!\n"); + } else { WriteSTSC( 2 ); } + stsd_vide->WriteContent( ); + stco_vide->WriteContent( ); + stsc_vide->WriteContent( ); + stts_vide->WriteContent( ); + stbl_vide->WriteContent( ); + dref_vide->WriteContent( ); + dinf_vide->WriteContent( ); + minf_vide->WriteContent( ); + mdia_vide->WriteContent( ); + + stsd_soun->WriteContent( ); + stco_soun->WriteContent( ); + stsc_soun->WriteContent( ); + stts_soun->WriteContent( ); + stbl_soun->WriteContent( ); + dref_soun->WriteContent( ); + dinf_soun->WriteContent( ); + minf_soun->WriteContent( ); + mdia_soun->WriteContent( ); + + trak_vide->WriteContent( ); + trak_soun->WriteContent( ); + + mvex->WriteContent( ); + moov->WriteContent( ); + + amhp->WriteContent( ); + rtmp->WriteContent( ); + + afrt->WriteContent( ); + asrt->WriteContent( ); + abst->WriteContent( ); + + trun_soun->WriteContent( ); + traf_soun->WriteContent( ); + + trun_vide->WriteContent( ); + traf_vide->WriteContent( ); + + moof->WriteContent( ); +} + +bool Interface::AllBoxesExist() { + return ( ftyp && moov && mvhd && trak_vide && tkhd_vide && mdia_vide && mdhd_vide && hdlr_vide && + minf_vide && vmhd_vide && dinf_vide && dref_vide && url_vide && stbl_vide && stts_vide && stsc_vide && + stco_vide && stsd_vide && avcC_vide && trak_soun && tkhd_soun && mdia_soun && mdhd_soun && hdlr_soun && + minf_soun && smhd_soun && dinf_soun && dref_soun && url_soun && stbl_soun && stts_soun && stsc_soun && + stco_soun && stsd_soun && esds_soun && rtmp && amhp && mvex && trex_vide && trex_soun && afrt && asrt + && abst && moof && mfhd && traf_vide && tfhd_vide && trun_vide && traf_soun && tfhd_soun && trun_soun ); +} + +void Interface::SetWidth( uint16_t NewWidth ) { + if( Width != NewWidth ) { + Width = NewWidth; + avcC_vide->SetWidth( Width ); + tkhd_vide->SetWidth( Width ); + } +} + +void Interface::SetHeight( uint16_t NewHeight ) { + if( Height != NewHeight ) { + Height = NewHeight; + avcC_vide->SetHeight( Height ); + tkhd_vide->SetHeight( Height ); + } +} + +void Interface::SetDurationTime( uint32_t NewDuration, uint32_t Track ) { + if( Duration.size() < Track ) { Duration.resize(Track+1); } + if( Duration[Track] != NewDuration ) { + Duration[Track] = NewDuration; + switch( Track ) { + case 0: + mvhd->SetDurationTime( Duration[Track] ); + break; + case 1: + mdhd_vide->SetDurationTime( Duration[Track] ); + tkhd_vide->SetDurationTime( Duration[Track] ); + break; + case 2: + mdhd_soun->SetDurationTime( Duration[Track] ); + tkhd_soun->SetDurationTime( Duration[Track] ); + break; + default: + fprintf( stderr, "WARNING, Setting Duration for track %d does have any effect\n", Track ); + break; + } + } +} +void Interface::SetTimeScale( uint32_t NewUnitsPerSecond, uint32_t Track ) { + if( UnitsPerSecond.size() < Track ) { UnitsPerSecond.resize(Track+1); } + if( UnitsPerSecond[Track] != NewUnitsPerSecond ) { + UnitsPerSecond[Track] = NewUnitsPerSecond; + switch(Track) { + case 0: + mvhd->SetTimeScale( UnitsPerSecond[Track] ); + break; + case 1: + mdhd_vide->SetTimeScale( UnitsPerSecond[Track] ); + break; + case 2: + mdhd_soun->SetTimeScale( UnitsPerSecond[Track] ); + break; + default: + fprintf( stderr, "WARNING, Setting Timescale for track %d does have any effect\n", Track ); + break; + } + } +} + +void Interface::SetStaticDefaults() { +// 'vide' = 0x76696465 + hdlr_vide->SetHandlerType( 0x76696465 ); + hdlr_vide->SetName( "Video Track" ); +// 'soun' = 0x736F756E + hdlr_soun->SetHandlerType( 0x736F756E ); + hdlr_vide->SetName( "Audio Track" ); +// Set Track ID's + tkhd_vide->SetTrackID( 1 ); + tkhd_soun->SetTrackID( 2 ); + trex_vide->SetTrackID( 1 ); + trex_soun->SetTrackID( 2 ); +// Set amhp entry + amhp->AddEntry( 1, 0, 0 ); +} + +void Interface::AddSTTSEntry( uint32_t SampleCount, uint32_t SampleDelta, uint32_t Track ) { + stts_record temp; + temp.SampleCount = SampleCount; + temp.SampleDelta = SampleDelta; + switch(Track) { + case 1: + sttsvide.push_back(temp); + break; + case 2: + sttssoun.push_back(temp); + break; + default: + fprintf( stderr, "WARNING: Track %d does not exist, STTS not added\n", Track ); + break; + } +} + +void Interface::EmptySTTS( uint32_t Track ) { + switch(Track) { + case 1: + sttsvide.clear(); + break; + case 2: + sttssoun.clear(); + break; + default: + fprintf( stderr, "WARNING: Track %d does not exist, STTS not cleared\n", Track ); + break; + } +} + +void Interface::WriteSTTS( uint32_t Track ) { + switch( Track ) { + case 1: + for( int i = sttsvide.size() -1; i > 0; i -- ) { + stts_vide->AddEntry(sttsvide[i].SampleCount,sttsvide[i].SampleDelta,i); + } + break; + case 2: + for( int i = sttssoun.size() -1; i > 0; i -- ) { + stts_soun->AddEntry(sttssoun[i].SampleCount,sttssoun[i].SampleDelta,i); + } + break; + default: + fprintf( stderr, "WARNING: Track %d does not exist, STTS not written\n", Track ); + break; + } +} + +void Interface::AddSTSCEntry( uint32_t FirstChunk, uint32_t SamplesPerChunk, uint32_t Track ) { + stsc_record temp; + temp.FirstChunk = FirstChunk; + temp.SamplesPerChunk = SamplesPerChunk; + temp.SampleDescIndex = 1; + switch(Track) { + case 1: + stscvide.push_back(temp); + break; + case 2: + stscsoun.push_back(temp); + break; + default: + fprintf( stderr, "WARNING: Track %d does not exist, STSC not added\n", Track ); + break; + } +} + +void Interface::EmptySTSC( uint32_t Track ) { + switch(Track) { + case 1: + stscvide.clear(); + break; + case 2: + stscsoun.clear(); + break; + default: + fprintf( stderr, "WARNING: Track %d does not exist, STSC not cleared\n", Track ); + break; + } +} + +void Interface::WriteSTSC( uint32_t Track ) { + switch( Track ) { + case 1: + for( int i = stscvide.size() -1; i > 0; i -- ) { + stsc_vide->AddEntry(stscvide[i].FirstChunk,stscvide[i].SamplesPerChunk,1,i); + } + break; + case 2: + for( int i = stscsoun.size() -1; i > 0; i -- ) { + stsc_soun->AddEntry(stscsoun[i].FirstChunk,stscsoun[i].SamplesPerChunk,1,i); + } + break; + default: + fprintf( stderr, "WARNING: Track %d does not exist, STSC not written\n", Track ); + break; + } +} + +void Interface::SetOffsets( std::vector NewOffsets, uint32_t Track ) { + switch( Track ) { + case 1: + stco_vide->SetOffsets( NewOffsets ); + break; + case 2: + stco_soun->SetOffsets( NewOffsets ); + break; + default: + fprintf( stderr, "WARNING: Track %d does not exist, Offsets not written\n", Track ); + break; + } +} + +std::string Interface::GenerateLiveBootstrap( uint32_t CurMediaTime ) { + //SetUpAFRT + afrt->SetUpdate(false); + afrt->SetTimeScale( 1000 ); + afrt->AddQualityEntry( "" ); + afrt->AddFragmentRunEntry( 1, 0, 0, 2 ); + afrt->WriteContent( ); + + //SetUpASRT + asrt->SetUpdate(false); + asrt->AddQualityEntry( "" ); + asrt->AddSegmentRunEntry( 1, 0 ); + asrt->WriteContent( ); + + //SetUpABST + abst->SetBootstrapVersion( 1 ); + abst->SetProfile( 0 ); + abst->SetLive( true ); + abst->SetUpdate( false ); + abst->SetTimeScale( 1000 ); + abst->SetMediaTime( CurMediaTime ); + abst->SetSMPTE( 0 ); + abst->SetMovieIdentifier( "" ); + abst->SetDRM( "" ); + abst->SetMetaData( "" ); + abst->AddServerEntry( "" ); + abst->AddQualityEntry( "" ); + abst->WriteContent( ); + + std::string Result; + Result.append( (char*)abst->GetBox( )->GetBoxedData( ), (int)abst->GetBox( )->GetBoxedDataSize( ) ); + return Result; +} + +std::string Interface::mdatFold(std::string data){ + static Box_mdat * mdat = new Box_mdat; + std::string Result; + mdat->SetContent((uint8_t*)data.c_str(), data.size()); + Result.append((char*)mdat->GetBox()->GetBoxedData(), (int)mdat->GetBox()->GetBoxedDataSize()); + return Result; +} diff --git a/util/MP4/main.cpp b/util/MP4/main.cpp new file mode 100644 index 00000000..027ddb8d --- /dev/null +++ b/util/MP4/main.cpp @@ -0,0 +1,13 @@ +#include +#include "interface.h" + +int main( ) { + std::cout << "Creating Interface\n"; + Interface * file = new Interface(); + std::cout << "Interface created, start linking them\n"; + file->link(); + std::cout << "Linking finished, deleting boxes\n"; + delete file; + std::cout << "Interface deleted\n"; + return 0; +}