diff --git a/Project/GNU/CLI/Makefile.am b/Project/GNU/CLI/Makefile.am index bba02fc..868f51a 100644 --- a/Project/GNU/CLI/Makefile.am +++ b/Project/GNU/CLI/Makefile.am @@ -25,10 +25,15 @@ movmetaedit_SOURCES = \ ../../../Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxx_clli.cpp \ ../../../Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxxSound.cpp \ ../../../Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxx_chan.cpp \ + ../../../Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxxUnknown.cpp \ ../../../Source/Common/mp4/mp4_moov_trak_mdia_minf_vmhd.cpp \ ../../../Source/Common/mp4/mp4_moov_trak_mdia_minf_smhd.cpp \ + ../../../Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd.cpp \ + ../../../Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd_tmcd.cpp \ ../../../Source/Common/mp4/mp4_moov_trak_mdia_mdhd.cpp \ ../../../Source/Common/mp4/mp4_moov_trak_tkhd.cpp \ + ../../../Source/Common/mp4/mp4_moov_trak_tref.cpp \ + ../../../Source/Common/mp4/mp4_moov_trak_tref_tmcd.cpp \ ../../../Source/Common/mp4/mp4_moov_meta.cpp \ ../../../Source/Common/mp4/mp4_moov_meta_hdlr.cpp \ ../../../Source/Common/mp4/mp4_moov_meta_ilst.cpp \ diff --git a/Project/MSVC2017/CLI/MOVMetaEdit_CLI.vcxproj b/Project/MSVC2017/CLI/MOVMetaEdit_CLI.vcxproj index 7b4b1ba..bbe16bc 100644 --- a/Project/MSVC2017/CLI/MOVMetaEdit_CLI.vcxproj +++ b/Project/MSVC2017/CLI/MOVMetaEdit_CLI.vcxproj @@ -47,9 +47,14 @@ + + + + + diff --git a/Project/Qt/movmetaedit-gui.pro b/Project/Qt/movmetaedit-gui.pro index bf038e3..66561f2 100644 --- a/Project/Qt/movmetaedit-gui.pro +++ b/Project/Qt/movmetaedit-gui.pro @@ -85,9 +85,14 @@ SOURCES += \ ../../Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxx_clli.cpp \ ../../Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxxSound.cpp \ ../../Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxx_chan.cpp \ + ../../Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxxUnknown.cpp \ ../../Source/Common/mp4/mp4_moov_trak_mdia_mdhd.cpp \ ../../Source/Common/mp4/mp4_moov_trak_mdia_minf_vmhd.cpp \ ../../Source/Common/mp4/mp4_moov_trak_mdia_minf_smhd.cpp \ + ../../Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd.cpp \ + ../../Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd_tmcd.cpp \ + ../../Source/Common/mp4/mp4_moov_trak_tref.cpp \ + ../../Source/Common/mp4/mp4_moov_trak_tref_tmcd.cpp \ ../../Source/Common/mp4/mp4_moov_meta.cpp \ ../../Source/Common/mp4/mp4_moov_meta_hdlr.cpp \ ../../Source/Common/mp4/mp4_moov_meta_ilst.cpp \ diff --git a/Source/CLI/Help.cpp b/Source/CLI/Help.cpp index 833fcdf..0deb721 100644 --- a/Source/CLI/Help.cpp +++ b/Source/CLI/Help.cpp @@ -151,6 +151,10 @@ ReturnValue Help_Tech(bool WithExamples) TEXTOUT(" Read HDR values from DolbyLabsMDF XML"); TEXTOUT(" --from-id VALUE"); TEXTOUT(" Read HDR values from the MasteringDisplay with the the specified ID in the XML"); + TEXTOUT("Options related to the timecode track:"); + TEXTOUT(" --timecode-delete"); + TEXTOUT(" Remove the timecode track and all related references atoms"); + TEXTOUT(""); TEXTOUT("Options related to the media header atom:"); TEXTOUT(" --language, --languages VALUE"); TEXTOUT(" Modify the media header language to VALUE for the specified audio track, \"[trackIndex=]lang[,[trackIndex=]lang...]\" format, e.g en,fr or 0=eng,1=fra"); diff --git a/Source/Common/mp4/mp4_.h b/Source/Common/mp4/mp4_.h index 2ba119e..d2fa648 100644 --- a/Source/Common/mp4/mp4_.h +++ b/Source/Common/mp4/mp4_.h @@ -58,10 +58,16 @@ namespace Elements const uint32_t moov_trak_mdia_minf_stbl_stsd_xxxx_clli = 0x636C6C69; const uint32_t moov_trak_mdia_minf_stbl_stsd_xxxxSound = 0xFFFFFFFF; const uint32_t moov_trak_mdia_minf_stbl_stsd_xxxx_chan = 0x6368616E; + const uint32_t moov_trak_mdia_minf_stbl_stsd_xxxxUnknown = 0xFFFFFFFF; + const uint32_t moov_trak_mdia_minf_stbl_stsd_tmcd = 0x746D6364; const uint32_t moov_trak_mdia_minf_vmhd = 0x766D6864; const uint32_t moov_trak_mdia_minf_smhd = 0x736D6864; + const uint32_t moov_trak_mdia_minf_gmhd = 0x676D6864; + const uint32_t moov_trak_mdia_minf_gmhd_tmcd = 0x746D6364; const uint32_t moov_trak_mdia_mdhd = 0x6D646864; const uint32_t moov_trak_tkhd = 0x746B6864; + const uint32_t moov_trak_tref = 0x74726566; + const uint32_t moov_trak_tref_tmcd = 0x746D6364; const uint32_t moov_meta = 0x6D657461; const uint32_t moov_meta_hdlr = 0x68646C72; const uint32_t moov_meta_keys = 0x6B657973; @@ -140,10 +146,15 @@ CHUNK_W(8, moov_trak_mdia_minf_stbl_stsd_xxxx_mdcv); CHUNK_W(8, moov_trak_mdia_minf_stbl_stsd_xxxx_clli); CHUNK_I(7, moov_trak_mdia_minf_stbl_stsd_xxxxSound); CHUNK_W(8, moov_trak_mdia_minf_stbl_stsd_xxxx_chan); +CHUNK__(7, moov_trak_mdia_minf_stbl_stsd_xxxxUnknown); CHUNK__(5, moov_trak_mdia_minf_vmhd); CHUNK__(5, moov_trak_mdia_minf_smhd); +CHUNK__(5, moov_trak_mdia_minf_gmhd); +CHUNK__(5, moov_trak_mdia_minf_gmhd_tmcd); CHUNK_W(4, moov_trak_mdia_mdhd); CHUNK_W(3, moov_trak_tkhd); +CHUNK__(3, moov_trak_tref); +CHUNK_W(4, moov_trak_tref_tmcd); CHUNK_I(2, moov_meta); CHUNK_W(3, moov_meta_hdlr); CHUNK_W(3, moov_meta_ilst); diff --git a/Source/Common/mp4/mp4_moov_trak.cpp b/Source/Common/mp4/mp4_moov_trak.cpp index 90f2f58..b7bb834 100644 --- a/Source/Common/mp4/mp4_moov_trak.cpp +++ b/Source/Common/mp4/mp4_moov_trak.cpp @@ -23,6 +23,7 @@ void mp4_moov_trak::Read_Internal () SUBS_BEGIN(); SUB_ELEMENT(moov_trak_tkhd); SUB_ELEMENT(moov_trak_tapt); + SUB_ELEMENT(moov_trak_tref); SUB_ELEMENT(moov_trak_mdia); SUBS_END(); } diff --git a/Source/Common/mp4/mp4_moov_trak_mdia_minf.cpp b/Source/Common/mp4/mp4_moov_trak_mdia_minf.cpp index fe65fe5..3bbadac 100644 --- a/Source/Common/mp4/mp4_moov_trak_mdia_minf.cpp +++ b/Source/Common/mp4/mp4_moov_trak_mdia_minf.cpp @@ -19,5 +19,6 @@ void mp4_moov_trak_mdia_minf::Read_Internal () SUB_ELEMENT(moov_trak_mdia_minf_stbl); SUB_ELEMENT(moov_trak_mdia_minf_vmhd); SUB_ELEMENT(moov_trak_mdia_minf_smhd); + SUB_ELEMENT(moov_trak_mdia_minf_gmhd); SUBS_END(); } diff --git a/Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd.cpp b/Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd.cpp new file mode 100644 index 0000000..a6733ed --- /dev/null +++ b/Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd.cpp @@ -0,0 +1,21 @@ +/* Copyright (c) MediaArea.net SARL. All Rights Reserved. + * + * Use of this source code is governed by a MIT-style license that can + * be found in the License.html file in the root of the source tree. + */ + +//--------------------------------------------------------------------------- +#include "Common/mp4/mp4_.h" +//--------------------------------------------------------------------------- + +//*************************************************************************** +// Read +//*************************************************************************** + +//--------------------------------------------------------------------------- +void mp4_moov_trak_mdia_minf_gmhd::Read_Internal () +{ + SUBS_BEGIN(); + SUB_ELEMENT(moov_trak_mdia_minf_gmhd_tmcd); + SUBS_END(); +} diff --git a/Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd_tmcd.cpp b/Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd_tmcd.cpp new file mode 100644 index 0000000..145d781 --- /dev/null +++ b/Source/Common/mp4/mp4_moov_trak_mdia_minf_gmhd_tmcd.cpp @@ -0,0 +1,19 @@ +/* Copyright (c) MediaArea.net SARL. All Rights Reserved. + * + * Use of this source code is governed by a MIT-style license that can + * be found in the License.html file in the root of the source tree. + */ + +//--------------------------------------------------------------------------- +#include "Common/mp4/mp4_.h" +//--------------------------------------------------------------------------- + +//*************************************************************************** +// Read +//*************************************************************************** + +//--------------------------------------------------------------------------- +void mp4_moov_trak_mdia_minf_gmhd_tmcd::Read_Internal () +{ + Global->moov_trak.back()->IsTimeCode=true; +} \ No newline at end of file diff --git a/Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd.cpp b/Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd.cpp index 84579d4..8d392a0 100644 --- a/Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd.cpp +++ b/Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd.cpp @@ -41,4 +41,10 @@ void mp4_moov_trak_mdia_minf_stbl_stsd::Read_Internal () SUB_ELEMENT_DEFAULT(moov_trak_mdia_minf_stbl_stsd_xxxxSound); SUBS_END_DEFAULT(); } + else + { + SUBS_BEGIN(); + SUB_ELEMENT_DEFAULT(moov_trak_mdia_minf_stbl_stsd_xxxxUnknown); + SUBS_END_DEFAULT(); + } } diff --git a/Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxxUnknown.cpp b/Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxxUnknown.cpp new file mode 100644 index 0000000..069ef16 --- /dev/null +++ b/Source/Common/mp4/mp4_moov_trak_mdia_minf_stbl_stsd_xxxxUnknown.cpp @@ -0,0 +1,23 @@ +/* Copyright (c) MediaArea.net SARL. All Rights Reserved. + * + * Use of this source code is governed by a MIT-style license that can + * be found in the License.html file in the root of the source tree. + */ + +//--------------------------------------------------------------------------- +#include "Common/mp4/mp4_.h" +//--------------------------------------------------------------------------- + +//*************************************************************************** +// Read +//*************************************************************************** + +//--------------------------------------------------------------------------- +void mp4_moov_trak_mdia_minf_stbl_stsd_xxxxUnknown::Read_Internal () +{ + if (Chunk.Header.Name==Elements::moov_trak_mdia_minf_stbl_stsd_tmcd) + { + Global->moov_trak.back()->moov_trak_mdia_minf_stbl_stsd_tmcd_Present=true; + Global->TimeCode_Track_Present=true; + } +} diff --git a/Source/Common/mp4/mp4_moov_trak_tref.cpp b/Source/Common/mp4/mp4_moov_trak_tref.cpp new file mode 100644 index 0000000..1a13de2 --- /dev/null +++ b/Source/Common/mp4/mp4_moov_trak_tref.cpp @@ -0,0 +1,21 @@ +/* Copyright (c) MediaArea.net SARL. All Rights Reserved. + * + * Use of this source code is governed by a MIT-style license that can + * be found in the License.html file in the root of the source tree. + */ + +//--------------------------------------------------------------------------- +#include "Common/mp4/mp4_.h" +//--------------------------------------------------------------------------- + +//*************************************************************************** +// Read +//*************************************************************************** + +//--------------------------------------------------------------------------- +void mp4_moov_trak_tref::Read_Internal () +{ + SUBS_BEGIN(); + SUB_ELEMENT(moov_trak_tref_tmcd); + SUBS_END(); +} diff --git a/Source/Common/mp4/mp4_moov_trak_tref_tmcd.cpp b/Source/Common/mp4/mp4_moov_trak_tref_tmcd.cpp new file mode 100644 index 0000000..06d245d --- /dev/null +++ b/Source/Common/mp4/mp4_moov_trak_tref_tmcd.cpp @@ -0,0 +1,47 @@ +/* Copyright (c) MediaArea.net SARL. All Rights Reserved. + * + * Use of this source code is governed by a MIT-style license that can + * be found in the License.html file in the root of the source tree. + */ + +//--------------------------------------------------------------------------- +#include "Common/mp4/mp4_.h" +//--------------------------------------------------------------------------- + +#include + +//*************************************************************************** +// Read +//*************************************************************************** + +//--------------------------------------------------------------------------- +void mp4_moov_trak_tref_tmcd::Read_Internal() +{ + Read_Internal_ReadAllInBuffer(); +} + +//*************************************************************************** +// Modify +//*************************************************************************** + +//--------------------------------------------------------------------------- +void mp4_moov_trak_tref_tmcd::Modify_Internal() +{ + if (Chunk.Content.IsModified) + return; + + if (Global->TimeCode_Track_Delete) + { + Chunk.Content.IsRemovable = true; + return; + } + + Chunk.Content.IsModified=true; + Chunk.Content.Size_IsModified=true; +} + +//--------------------------------------------------------------------------- +void mp4_moov_trak_tref_tmcd::Write_Internal() +{ + mp4_Base::Write_Internal(Chunk.Content.Buffer, (size_t)Chunk.Content.Size); +} diff --git a/Source/Common/mp4_Base.h b/Source/Common/mp4_Base.h index ab0c8ce..fb7e290 100644 --- a/Source/Common/mp4_Base.h +++ b/Source/Common/mp4_Base.h @@ -195,15 +195,19 @@ class mp4_Base { bool IsVideo; bool IsSound; + bool IsTimeCode; bool moov_trak_mdia_minf_stbl_stsd_xxxxVideo_Present; bool moov_trak_mdia_minf_stbl_stsd_xxxxSound_Present; + bool moov_trak_mdia_minf_stbl_stsd_tmcd_Present; block_moov_trak() { IsVideo=false; IsSound=false; + IsTimeCode=false; moov_trak_mdia_minf_stbl_stsd_xxxxVideo_Present=false; moov_trak_mdia_minf_stbl_stsd_xxxxSound_Present=false; + moov_trak_mdia_minf_stbl_stsd_tmcd_Present=false; } }; struct block_moov_trak_tapt_xxxx @@ -507,6 +511,8 @@ class mp4_Base vector moov_meta_ilst_NewValues; size_t moov_meta_ilst_AlreadyPresent; size_t moov_trak_FirstVideoIndex; + bool TimeCode_Track_Present; + bool TimeCode_Track_Delete; bool NewChunksAtTheEnd; bool Out_Buffer_File_TryModification; bool Out_Buffer_File_IsModified; @@ -543,6 +549,8 @@ class mp4_Base moov_meta_keys_AlreadyPresent=0; moov_meta_ilst_AlreadyPresent=0; moov_trak_FirstVideoIndex=(size_t)-1; + TimeCode_Track_Present=false; + TimeCode_Track_Delete=false; NewChunksAtTheEnd=false; Out_Buffer_WriteAtEnd=false; Out_Buffer_File_TryModification=true; diff --git a/Source/Common/mp4_Handler.cpp b/Source/Common/mp4_Handler.cpp index 42e406b..f6dbc2b 100644 --- a/Source/Common/mp4_Handler.cpp +++ b/Source/Common/mp4_Handler.cpp @@ -636,6 +636,54 @@ bool mp4_Handler::Save() } } } + + //Remove timecode tracks and chunks + if (Chunks->Global->TimeCode_Track_Delete) + { + size_t trak_Index=0; + for (size_t Pos=0; PosSubs.size(); Pos++) + { + if (Chunks->Subs[Pos]->Chunk.Header.Name==Elements::moov) + { + for (size_t Pos2=0; Pos2Subs[Pos]->Subs.size(); Pos2++) + { + for (size_t Pos3=0; Pos3Subs[Pos]->Subs[Pos2]->Subs.size(); Pos3++) + { + if (Chunks->Subs[Pos]->Subs[Pos2]->Subs[Pos3]->Chunk.Header.Name==Elements::moov_trak_tref) + { + for (size_t Pos4=0; Pos4Subs[Pos]->Subs[Pos2]->Subs[Pos3]->Subs.size(); Pos4++) + { + if (Chunks->Subs[Pos]->Subs[Pos2]->Subs[Pos3]->Subs[Pos4]->Chunk.Header.Name==Elements::moov_trak_tref_tmcd) + { + Chunks->Subs[Pos]->Subs[Pos2]->Modify(Elements::moov_trak_tref, Elements::moov_trak_tref_tmcd); + Chunks->Subs[Pos]->Chunk.Content.IsModified=true; + Chunks->Subs[Pos]->Chunk.Content.Size_IsModified=true; + Chunks->Chunk.Content.IsModified=true; + Chunks->Chunk.Content.Size_IsModified=true; + } + } + } + } + + if (Chunks->Subs[Pos]->Subs[Pos2]->Chunk.Header.Name==Elements::moov_trak) + { + Chunks->Subs[Pos]->Subs[Pos2]->Modify(Elements::moov_trak_tref, Elements::moov_trak_tref_tmcd); + if (trak_IndexGlobal->moov_trak.size() && Chunks->Global->moov_trak[trak_Index]->moov_trak_mdia_minf_stbl_stsd_tmcd_Present) + { + delete Chunks->Subs[Pos]->Subs[Pos2]; + Chunks->Subs[Pos]->Subs.erase(Chunks->Subs[Pos]->Subs.begin()+Pos2); + Chunks->Subs[Pos]->Chunk.Content.IsModified=true; + Chunks->Subs[Pos]->Chunk.Content.Size_IsModified=true; + Chunks->Chunk.Content.IsModified=true; + Chunks->Chunk.Content.Size_IsModified=true; + } + trak_Index++; + } + } + } + } + } + if (Chunks->Global->moov_trak_tkhd_Modified) Chunks->Modify(Elements::moov, Elements::moov_trak, Elements::moov_trak_tkhd); // Modify mdhd in all audio tracks @@ -936,6 +984,13 @@ string mp4_Handler::Get(const string &Field) return ss.str(); } + else if (Field=="tmcd") + { + if (Chunks->Global->TimeCode_Track_Present && !Chunks->Global->TimeCode_Track_Delete) + return "Present"; + + return string(); + } else if (Field=="lang") { stringstream ss; @@ -1950,6 +2005,11 @@ bool mp4_Handler::Remove(const string &Field) return true; } + else if (Field=="tmcd") + { + Chunks->Global->TimeCode_Track_Delete=true; + return true; + } else if (Field=="chan") { if (!Chunks->Global->moov_trak_mdia_minf_stbl_stsd_xxxx_chan.empty()) diff --git a/Source/movedit_main.cpp b/Source/movedit_main.cpp index 0bd83e9..6bda10e 100644 --- a/Source/movedit_main.cpp +++ b/Source/movedit_main.cpp @@ -59,6 +59,8 @@ int main(int argc, char* argv[]) std::string clap_New=string(); bool clap_Delete=false; bool clap_OK=true; + bool tmcd_Delete=false; + bool tmcd_OK=true; std::map lang_New; std::map lang_OK; std::map chan_New; @@ -527,6 +529,11 @@ int main(int argc, char* argv[]) } argp++; } + else if ((Ztring(argv[argp]) == __T("-timecode-delete") + || Ztring(argv[argp]) == __T("--timecode-delete"))) + { + tmcd_Delete=true; + } else if ((Ztring(argv[argp]) == __T("-channels") || Ztring(argv[argp]) == __T("--channels"))) { @@ -632,6 +639,7 @@ int main(int argc, char* argv[]) !lang_New.empty() || mdcv_Delete || clli_Delete || + tmcd_Delete || !luminance_New.empty() || !display_primaries_New.empty() || !maximum_content_light_level_New.empty() || @@ -792,7 +800,7 @@ int main(int argc, char* argv[]) cout << " it (empty)" << endl; cout << "M = The field will be modified ('Y') or should be modified but it is not possible" << endl; cout << " due to feature not implemented ('N')" << endl; - cout << FileNameFake << "|OK?|Clean Ap.|M| Prod Ap.|M| Enc. Ap.|M|vid. version|M|temp. quality|M| PAR|M| Display Primaries|M| Luminance|M| Max content light lev.|M| Max frame avg. light lev.|M|w-scale|M| Field|M| Color|M|Gamma|M| Aperture|M| Languages|M| Channels|M|" << endl; + cout << FileNameFake << "|OK?|Clean Ap.|M| Prod Ap.|M| Enc. Ap.|M|vid. version|M|temp. quality|M| PAR|M| Display Primaries|M| Luminance|M| Max content light lev.|M| Max frame avg. light lev.|M|w-scale|M| Field|M| Color|M|Gamma|M| Aperture|M|TimeCode|M| Languages|M| Channels|M|" << endl; } else cout << FileNameFake << "|OK?| Registry|UniversalAdId value" << endl; @@ -1059,6 +1067,8 @@ int main(int argc, char* argv[]) } else if (clap_Delete) H->Remove("clap"); + else if (tmcd_Delete) + H->Remove("tmcd"); if (!lang_New.empty()) { for (map::iterator It=lang_New.begin(); It!=lang_New.end(); It++) @@ -1165,7 +1175,10 @@ int main(int argc, char* argv[]) if (clap.size() < 25) clap.insert(0, 25 - clap.size(), ' '); cout << clap << "|" << ((!clap_New.empty() || clap_Delete) ? ((OK && clap_OK) ? "Y" : "N") : " ") << "|"; - + string tmcd = H->Get("tmcd"); + if (tmcd.size() < 8) + tmcd.insert(0, 8 - tmcd.size(), ' '); + cout << tmcd << "|" << (tmcd_Delete ? ((OK && tmcd_OK) ? "Y" : "N") : " ") << "|"; vectorlangs; string lang = H->Get("lang"); { @@ -1237,7 +1250,7 @@ int main(int argc, char* argv[]) for (size_t Pos=0; Pos