From 66e473db324af4abc17023828882b3247c6e1c8a Mon Sep 17 00:00:00 2001 From: Robin Mills Date: Sun, 7 Sep 2014 11:59:45 +0000 Subject: [PATCH] GSoC2013 Video Write Code. Thank You, Mahesh for a lot of hard work. And Thanks to Abhinav for mentoring. Great Job, Guys. --- CMakeLists.txt | 2 +- Makefile | 3 + config/Makefile.in | 3 + msvc2003/exiv2lib/exiv2lib.vcproj | 4 +- msvc2005/exiv2/exiv2.vcproj | 794 +----- msvc2005/exiv2lib/exiv2lib.vcproj | 105 +- msvc2012/exiv2lib/exiv2lib.vcxproj | 119 +- src/CMakeLists.txt | 4 + src/Makefile | 1 + src/actions.hpp | 86 +- src/asfvideo.cpp | 67 +- src/asfvideo.hpp | 12 +- src/error.hpp | 18 + src/image.cpp | 4 +- src/matroskavideo.cpp | 1465 ++++++----- src/matroskavideo.hpp | 156 +- src/quicktimevideo.cpp | 3862 ++++++++++++++++++---------- src/quicktimevideo.hpp | 289 ++- src/riffvideo.cpp | 1806 ++++++++----- src/riffvideo.hpp | 303 ++- src/tags_int.hpp | 12 + src/types.cpp | 7 +- src/types.hpp | 5 +- src/utilsvideo.cpp | 60 + src/utilsvideo.hpp | 42 + src/version.hpp | 1 + src/xmp.cpp | 2 + test/Makefile | 52 +- test/functions.source | 79 +- test/video-test.sh | 51 +- test/write-video-test.sh | 68 + 31 files changed, 5594 insertions(+), 3888 deletions(-) create mode 100644 src/utilsvideo.cpp create mode 100644 src/utilsvideo.hpp create mode 100755 test/write-video-test.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index a386903b..73de6c25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,7 +187,7 @@ ENDIF() ADD_CUSTOM_TARGET(tests COMMAND make test "EXIV2_BINDIR=${CMAKE_BINARY_DIR}/bin" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test/" ) ADD_CUSTOM_TARGET(teste COMMAND make teste "EXIV2_BINDIR=${CMAKE_BINARY_DIR}/bin" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test/" ) ADD_CUSTOM_TARGET(testv COMMAND make testv "EXIV2_BINDIR=${CMAKE_BINARY_DIR}/bin" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test/" ) - +ADD_CUSTOM_TARGET(testvw COMMAND make testvw "EXIV2_BINDIR=${CMAKE_BINARY_DIR}/bin" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test/" ) ## # http://dev.exiv2.org/boards/3/topics/1364 # effectively does a make doc on the root directory diff --git a/Makefile b/Makefile index 2d6be127..1d96c11e 100644 --- a/Makefile +++ b/Makefile @@ -79,6 +79,9 @@ teste: testv: cd test && $(MAKE) testv +testvw: + cd test && $(MAKE) testvw + MAJOR=$(shell grep "define.*EXIV2_.*_VERSION .*\\d*" src/version.hpp | grep MAJOR | sed -e 's/EXIV2//g' | tr -dC [:digit:]) MINOR=$(shell grep "define.*EXIV2_.*_VERSION .*\\d*" src/version.hpp | grep MINOR | sed -e 's/EXIV2//g' | tr -dC [:digit:]) VERSION=exiv2-$(MAJOR).$(MINOR) diff --git a/config/Makefile.in b/config/Makefile.in index d3fec78e..ecae1d0d 100644 --- a/config/Makefile.in +++ b/config/Makefile.in @@ -79,6 +79,9 @@ teste: testv: cd test && $(MAKE) testv +testvw: + cd test && $(MAKE) testvw + MAJOR=$(shell grep "define.*EXIV2_.*_VERSION .*\\d*" src/version.hpp | grep MAJOR | sed -e 's/EXIV2//g' | tr -dC [:digit:]) MINOR=$(shell grep "define.*EXIV2_.*_VERSION .*\\d*" src/version.hpp | grep MINOR | sed -e 's/EXIV2//g' | tr -dC [:digit:]) VERSION=exiv2-$(MAJOR).$(MINOR) diff --git a/msvc2003/exiv2lib/exiv2lib.vcproj b/msvc2003/exiv2lib/exiv2lib.vcproj index 1ce2b9f3..66fd2094 100644 --- a/msvc2003/exiv2lib/exiv2lib.vcproj +++ b/msvc2003/exiv2lib/exiv2lib.vcproj @@ -1,3 +1 @@ - - - + \ No newline at end of file diff --git a/msvc2005/exiv2/exiv2.vcproj b/msvc2005/exiv2/exiv2.vcproj index 13e99dac..af472da4 100644 --- a/msvc2005/exiv2/exiv2.vcproj +++ b/msvc2005/exiv2/exiv2.vcproj @@ -1,793 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/msvc2005/exiv2lib/exiv2lib.vcproj b/msvc2005/exiv2lib/exiv2lib.vcproj index 9899984d..26cde850 100644 --- a/msvc2005/exiv2lib/exiv2lib.vcproj +++ b/msvc2005/exiv2lib/exiv2lib.vcproj @@ -1,104 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/msvc2012/exiv2lib/exiv2lib.vcxproj b/msvc2012/exiv2lib/exiv2lib.vcxproj index 511d87e2..5555c69c 100644 --- a/msvc2012/exiv2lib/exiv2lib.vcxproj +++ b/msvc2012/exiv2lib/exiv2lib.vcxproj @@ -1,118 +1 @@ - -DebugDLLWin32DebugDLLx64DebugWin32Debugx64ReleaseDLLWin32ReleaseDLLx64ReleaseWin32Releasex64{831EF580-92C8-4CA8-B0CE-3D906280A54D}exiv2libWin32ProjDynamicLibraryv110MultiByteDynamicLibraryv110MultiByteStaticLibraryv110MultiByteStaticLibraryv110MultiByteDynamicLibraryv110MultiByteDynamicLibraryv110MultiByteStaticLibraryv110MultiByteStaticLibraryv110MultiByte - <_ProjectFileVersion>11.0.50727.1$(Platform)\$(Configuration)\build\$(Platform)\$(Configuration)\$(Platform)\$(Configuration)\build\$(Platform)\$(Configuration)\$(Platform)\$(Configuration)\build\$(Platform)\$(Configuration)\$(Platform)\$(Configuration)\build\$(Platform)\$(Configuration)\$(Platform)\$(Configuration)\build\$(Platform)\$(Configuration)\$(Platform)\$(Configuration)\build\$(Platform)\$(Configuration)\$(Platform)\$(Configuration)\build\$(Platform)\$(Configuration)\$(Platform)\$(Configuration)\build\$(Platform)\$(Configuration)\if exist ..\include\exiv2 goto :jail -mkdir ..\include\exiv2\ -copy/y ..\..\src\*.h ..\include\exiv2\ -copy/y ..\..\src\*.hpp ..\include\exiv2\ -cd ..\include\exiv2 -del *_int.hpp -cd ..\..\exiv2lib -:jail -Disabled../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories)WIN32;_DEBUG;%(PreprocessorDefinitions)trueEnableFastChecksMultiThreadedDebugtruetruetrueLevel3falseProgramDatabase$(OutDir)exiv2sd.lib..\xmpsdk\$(Platform)\$(Configuration);..\expat\(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)msvcrtd;%(IgnoreSpecificDefaultLibraries)if exist ..\include\exiv2 goto :jail -mkdir ..\include\exiv2\ -copy/y ..\..\src\*.h ..\include\exiv2\ -copy/y ..\..\src\*.hpp ..\include\exiv2\ -cd ..\include\exiv2 -del *_int.hpp -cd ..\..\exiv2lib -:jail -X64Disabled../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories)WIN32;_DEBUG;%(PreprocessorDefinitions)trueEnableFastChecksMultiThreadedDebugtruetruetrueLevel3falseProgramDatabase$(OutDir)exiv2sd.lib..\xmpsdk\$(Platform)\$(Configuration);..\expat\(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)msvcrtd;%(IgnoreSpecificDefaultLibraries)copy expat and zlib binariesif exist ..\include\exiv2 goto :jail -mkdir ..\include\exiv2\ -copy/y ..\..\src\*.h ..\include\exiv2\ -copy/y ..\..\src\*.hpp ..\include\exiv2\ -cd ..\include\exiv2 -del *_int.hpp -cd ..\..\exiv2lib -:jail - -../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories)WIN32;_NDEBUG;%(PreprocessorDefinitions)MultiThreadedtruetrueLevel3falseProgramDatabase$(OutDir)exiv2s.lib..\xmpsdk\$(Platform)\$(Configuration);..\expat\(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)msvcrt;%(IgnoreSpecificDefaultLibraries)copy expat and zlib binariesif exist ..\include\exiv2 goto :jail -mkdir ..\include\exiv2\ -copy/y ..\..\src\*.h ..\include\exiv2\ -copy/y ..\..\src\*.hpp ..\include\exiv2\ -cd ..\include\exiv2 -del *_int.hpp -cd ..\..\exiv2lib -:jail - -X64../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories)WIN32;_NDEBUG;%(PreprocessorDefinitions)MultiThreadedtruetrueLevel3falseProgramDatabase$(OutDir)exiv2s.lib..\xmpsdk\$(Platform)\$(Configuration);..\expat\(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)msvcrt;%(IgnoreSpecificDefaultLibraries)copy expat and zlib dllsif exist ..\include\exiv2 goto :jail -mkdir ..\include\exiv2\ -copy/y ..\..\src\*.h ..\include\exiv2\ -copy/y ..\..\src\*.hpp ..\include\exiv2\ -cd ..\include\exiv2 -del *_int.hpp -cd ..\..\exiv2lib -:jail -if NOT EXIST "$(OutDir)" mkdir "$(OutDir)" -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" -Disabled../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories)WIN32;_DEBUG;EXV_HAVE_DLL;EXV_BUILDING_LIB;%(PreprocessorDefinitions)trueEnableFastChecksMultiThreadedDebugDLLtruetruetrueLevel3falseProgramDatabasefalse/NODEFAULTLIB:LIBMTD %(AdditionalOptions)..\xmpsdk\$(Platform)\$(Configuration)\xmpsdk.lib;..\expat\$(Platform)\$(Configuration)\libexpat.lib;..\zlib\$(Platform)\$(Configuration)\zlib1d.lib;%(AdditionalDependencies)$(OutDir)exiv2d.dlltrue$(TargetDir)\exiv2d.libMachineX86copy dlls to the build directorysetlocal -set X=$(TargetDir) -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "%25X%25" -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.lib" "%25X%25" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "%25X%25" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.lib" "%25X%25" - - -copy expat and zlib dllsif exist ..\include\exiv2 goto :jail -mkdir ..\include\exiv2\ -copy/y ..\..\src\*.h ..\include\exiv2\ -copy/y ..\..\src\*.hpp ..\include\exiv2\ -cd ..\include\exiv2 -del *_int.hpp -cd ..\..\exiv2lib -:jail -if NOT EXIST "$(OutDir)" mkdir "$(OutDir)" -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" - -X64Disabled../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories)WIN32;_DEBUG;EXV_HAVE_DLL;EXV_BUILDING_LIB;%(PreprocessorDefinitions)trueEnableFastChecksMultiThreadedDebugDLLtruetruetrueLevel3falseProgramDatabasefalse/NODEFAULTLIB:LIBMTD %(AdditionalOptions)..\xmpsdk\$(Platform)\$(Configuration)\xmpsdk.lib;..\expat\$(Platform)\$(Configuration)\libexpat.lib;..\zlib\$(Platform)\$(Configuration)\zlib1d.lib;%(AdditionalDependencies)$(OutDir)exiv2d.dlltrue$(TargetDir)\exiv2d.libMachineX64copy dlls to the build directorysetlocal -set X=$(TargetDir) -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "%25X%25" -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.lib" "%25X%25" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "%25X%25" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.lib" "%25X%25" - -copy expat and zlib dllsif exist ..\include\exiv2 goto :jail -mkdir ..\include\exiv2\ -copy/y ..\..\src\*.h ..\include\exiv2\ -copy/y ..\..\src\*.hpp ..\include\exiv2\ -cd ..\include\exiv2 -del *_int.hpp -cd ..\..\exiv2lib -:jail -if NOT EXIST "$(OutDir)" mkdir "$(OutDir)" -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" - -MinSpace../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories)WIN32;_NDEBUG;EXV_HAVE_DLL;EXV_BUILDING_LIB;%(PreprocessorDefinitions)trueDefaultMultiThreadedDLLtruetruetrueLevel3falseProgramDatabasefalse..\xmpsdk\$(Platform)\$(Configuration)\xmpsdk.lib;..\expat\$(Platform)\$(Configuration)\libexpat.lib;..\zlib\$(Platform)\$(Configuration)\zlib1.lib;%(AdditionalDependencies)$(OutDir)exiv2.dllfalse$(TargetDir)\exiv2.libMachineX86copy dlls to the build directorysetlocal -set X=$(TargetDir) -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "%25X%25" -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.lib" "%25X%25" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "%25X%25" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.lib" "%25X%25" - -copy expat and zlib dllsif exist ..\include\exiv2 goto :jail -mkdir ..\include\exiv2\ -copy/y ..\..\src\*.h ..\include\exiv2\ -copy/y ..\..\src\*.hpp ..\include\exiv2\ -cd ..\include\exiv2 -del *_int.hpp -cd ..\..\exiv2lib -:jail -if NOT EXIST "$(OutDir)" mkdir "$(OutDir)" -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" - - -X64MinSpace../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories)WIN32;_NDEBUG;EXV_HAVE_DLL;EXV_BUILDING_LIB;%(PreprocessorDefinitions)trueDefaultMultiThreadedDLLtruetruetrueLevel3falseProgramDatabasefalse..\xmpsdk\$(Platform)\$(Configuration)\xmpsdk.lib;..\expat\$(Platform)\$(Configuration)\libexpat.lib;..\zlib\$(Platform)\$(Configuration)\zlib1.lib;%(AdditionalDependencies)$(OutDir)exiv2.dllfalse$(TargetDir)\exiv2.libMachineX64copy dlls to the build directorysetlocal -set X=$(TargetDir) -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "%25X%25" -copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.lib" "%25X%25" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "%25X%25" -copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.lib" "%25X%25" - - - - -{6c4c06a3-6f8f-4067-aa4c-d5f41e1fff9a}false{09877cf4-83b6-44fe-a2e2-629aa5c8093e}false{8308c68d-e12b-4c71-96f4-7137f6beb654}false - + DebugDLL Win32 DebugDLL x64 Debug Win32 Debug x64 ReleaseDLL Win32 ReleaseDLL x64 Release Win32 Release x64 {831EF580-92C8-4CA8-B0CE-3D906280A54D} exiv2lib Win32Proj DynamicLibrary v110 MultiByte DynamicLibrary v110 MultiByte StaticLibrary v110 MultiByte StaticLibrary v110 MultiByte DynamicLibrary v110 MultiByte DynamicLibrary v110 MultiByte StaticLibrary v110 MultiByte StaticLibrary v110 MultiByte <_ProjectFileVersion>11.0.50727.1 $(Platform)\$(Configuration)\ build\$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ build\$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ build\$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ build\$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ build\$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ build\$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ build\$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ build\$(Platform)\$(Configuration)\ if exist ..\include\exiv2 goto :jailmkdir ..\include\exiv2\copy/y ..\..\src\*.h ..\include\exiv2\copy/y ..\..\src\*.hpp ..\include\exiv2\cd ..\include\exiv2del *_int.hppcd ..\..\exiv2lib:jail Disabled ../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories) WIN32;_DEBUG;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug true true true Level3 false ProgramDatabase $(OutDir)exiv2sd.lib ..\xmpsdk\$(Platform)\$(Configuration);..\expat\(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) msvcrtd;%(IgnoreSpecificDefaultLibraries) if exist ..\include\exiv2 goto :jailmkdir ..\include\exiv2\copy/y ..\..\src\*.h ..\include\exiv2\copy/y ..\..\src\*.hpp ..\include\exiv2\cd ..\include\exiv2del *_int.hppcd ..\..\exiv2lib:jail X64 Disabled ../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories) WIN32;_DEBUG;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug true true true Level3 false ProgramDatabase $(OutDir)exiv2sd.lib ..\xmpsdk\$(Platform)\$(Configuration);..\expat\(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) msvcrtd;%(IgnoreSpecificDefaultLibraries) copy expat and zlib binaries if exist ..\include\exiv2 goto :jailmkdir ..\include\exiv2\copy/y ..\..\src\*.h ..\include\exiv2\copy/y ..\..\src\*.hpp ..\include\exiv2\cd ..\include\exiv2del *_int.hppcd ..\..\exiv2lib:jail ../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories) WIN32;_NDEBUG;%(PreprocessorDefinitions) MultiThreaded true true Level3 false ProgramDatabase $(OutDir)exiv2s.lib ..\xmpsdk\$(Platform)\$(Configuration);..\expat\(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) msvcrt;%(IgnoreSpecificDefaultLibraries) copy expat and zlib binaries if exist ..\include\exiv2 goto :jailmkdir ..\include\exiv2\copy/y ..\..\src\*.h ..\include\exiv2\copy/y ..\..\src\*.hpp ..\include\exiv2\cd ..\include\exiv2del *_int.hppcd ..\..\exiv2lib:jail X64 ../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories) WIN32;_NDEBUG;%(PreprocessorDefinitions) MultiThreaded true true Level3 false ProgramDatabase $(OutDir)exiv2s.lib ..\xmpsdk\$(Platform)\$(Configuration);..\expat\(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) msvcrt;%(IgnoreSpecificDefaultLibraries) copy expat and zlib dlls if exist ..\include\exiv2 goto :jailmkdir ..\include\exiv2\copy/y ..\..\src\*.h ..\include\exiv2\copy/y ..\..\src\*.hpp ..\include\exiv2\cd ..\include\exiv2del *_int.hppcd ..\..\exiv2lib:jailif NOT EXIST "$(OutDir)" mkdir "$(OutDir)"copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "$(OutDir)"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" Disabled ../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories) WIN32;_DEBUG;EXV_HAVE_DLL;EXV_BUILDING_LIB;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL true true true Level3 false ProgramDatabase false /NODEFAULTLIB:LIBMTD %(AdditionalOptions) ..\xmpsdk\$(Platform)\$(Configuration)\xmpsdk.lib;..\expat\$(Platform)\$(Configuration)\libexpat.lib;..\zlib\$(Platform)\$(Configuration)\zlib1d.lib;%(AdditionalDependencies) $(OutDir)exiv2d.dll true $(TargetDir)\exiv2d.lib MachineX86 copy dlls to the build directory setlocalset X=$(TargetDir)copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "%25X%25"copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.lib" "%25X%25"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "%25X%25"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.lib" "%25X%25" copy expat and zlib dlls if exist ..\include\exiv2 goto :jailmkdir ..\include\exiv2\copy/y ..\..\src\*.h ..\include\exiv2\copy/y ..\..\src\*.hpp ..\include\exiv2\cd ..\include\exiv2del *_int.hppcd ..\..\exiv2lib:jailif NOT EXIST "$(OutDir)" mkdir "$(OutDir)"copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "$(OutDir)"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" X64 Disabled ../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories) WIN32;_DEBUG;EXV_HAVE_DLL;EXV_BUILDING_LIB;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL true true true Level3 false ProgramDatabase false /NODEFAULTLIB:LIBMTD %(AdditionalOptions) ..\xmpsdk\$(Platform)\$(Configuration)\xmpsdk.lib;..\expat\$(Platform)\$(Configuration)\libexpat.lib;..\zlib\$(Platform)\$(Configuration)\zlib1d.lib;%(AdditionalDependencies) $(OutDir)exiv2d.dll true $(TargetDir)\exiv2d.lib MachineX64 copy dlls to the build directory setlocalset X=$(TargetDir)copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "%25X%25"copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.lib" "%25X%25"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "%25X%25"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.lib" "%25X%25" copy expat and zlib dlls if exist ..\include\exiv2 goto :jailmkdir ..\include\exiv2\copy/y ..\..\src\*.h ..\include\exiv2\copy/y ..\..\src\*.hpp ..\include\exiv2\cd ..\include\exiv2del *_int.hppcd ..\..\exiv2lib:jailif NOT EXIST "$(OutDir)" mkdir "$(OutDir)"copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "$(OutDir)"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" MinSpace ../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories) WIN32;_NDEBUG;EXV_HAVE_DLL;EXV_BUILDING_LIB;%(PreprocessorDefinitions) true Default MultiThreadedDLL true true true Level3 false ProgramDatabase false ..\xmpsdk\$(Platform)\$(Configuration)\xmpsdk.lib;..\expat\$(Platform)\$(Configuration)\libexpat.lib;..\zlib\$(Platform)\$(Configuration)\zlib1.lib;%(AdditionalDependencies) $(OutDir)exiv2.dll false $(TargetDir)\exiv2.lib MachineX86 copy dlls to the build directory setlocalset X=$(TargetDir)copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "%25X%25"copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.lib" "%25X%25"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "%25X%25"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.lib" "%25X%25" copy expat and zlib dlls if exist ..\include\exiv2 goto :jailmkdir ..\include\exiv2\copy/y ..\..\src\*.h ..\include\exiv2\copy/y ..\..\src\*.hpp ..\include\exiv2\cd ..\include\exiv2del *_int.hppcd ..\..\exiv2lib:jailif NOT EXIST "$(OutDir)" mkdir "$(OutDir)"copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "$(OutDir)"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "$(OutDir)" X64 MinSpace ../include;../include/exiv2;../../src;../../xmpsdk/include;../../xmpsdk/src;../../../expat-2.1.0/lib;../../../zlib-1.2.7;%(AdditionalIncludeDirectories) WIN32;_NDEBUG;EXV_HAVE_DLL;EXV_BUILDING_LIB;%(PreprocessorDefinitions) true Default MultiThreadedDLL true true true Level3 false ProgramDatabase false ..\xmpsdk\$(Platform)\$(Configuration)\xmpsdk.lib;..\expat\$(Platform)\$(Configuration)\libexpat.lib;..\zlib\$(Platform)\$(Configuration)\zlib1.lib;%(AdditionalDependencies) $(OutDir)exiv2.dll false $(TargetDir)\exiv2.lib MachineX64 copy dlls to the build directory setlocalset X=$(TargetDir)copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.dll" "%25X%25"copy/y "$(SolutionDir)expat\$(Platform)\$(Configuration)\*.lib" "%25X%25"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.dll" "%25X%25"copy/y "$(SolutionDir)zlib\$(Platform)\$(Configuration)\*.lib" "%25X%25" {6c4c06a3-6f8f-4067-aa4c-d5f41e1fff9a} false {09877cf4-83b6-44fe-a2e2-629aa5c8093e} false {8308c68d-e12b-4c71-96f4-7137f6beb654} false \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9879f836..b9815fe0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -72,10 +72,12 @@ SET( LIBEXIV2_HDR asfvideo.hpp tgaimage.hpp tiffimage.hpp types.hpp + utilsvideo.hpp value.hpp version.hpp xmp.hpp xmpsidecar.hpp + utilsvideo.hpp ) # Add library C++ source files to this list @@ -127,10 +129,12 @@ SET( LIBEXIV2_SRC asfvideo.cpp tiffimage.cpp tiffvisitor.cpp types.cpp + utilsvideo.cpp value.cpp version.cpp xmp.cpp xmpsidecar.cpp + utilsvideo.cpp ) ## diff --git a/src/Makefile b/src/Makefile index 72fe0ded..99ff9750 100644 --- a/src/Makefile +++ b/src/Makefile @@ -117,6 +117,7 @@ CCSRC += preview.cpp \ tiffimage.cpp \ tiffvisitor.cpp \ types.cpp \ + utilsvideo.cpp \ value.cpp \ version.cpp \ xmp.cpp \ diff --git a/src/actions.hpp b/src/actions.hpp index bf0c8547..1cf8d275 100644 --- a/src/actions.hpp +++ b/src/actions.hpp @@ -159,7 +159,11 @@ namespace Action { public: virtual ~Print(); virtual int run(const std::string& path); - typedef std::auto_ptr AutoPtr; + typedef std::auto_ptr AutoPtr; //!< TODO + /*! + * \brief clone TODO + * \return + */ AutoPtr clone() const; //! Print the Jpeg comment @@ -212,10 +216,18 @@ namespace Action { public: virtual ~Rename(); virtual int run(const std::string& path); - typedef std::auto_ptr AutoPtr; + typedef std::auto_ptr AutoPtr; //!< TODO + /*! + * \brief clone TODO + * \return + */ AutoPtr clone() const; private: + /*! + * \brief clone TODO + * \return + */ virtual Rename* clone_() const; }; // class Rename @@ -224,10 +236,18 @@ namespace Action { public: virtual ~Adjust(); virtual int run(const std::string& path); - typedef std::auto_ptr AutoPtr; + typedef std::auto_ptr AutoPtr; //!< TODO + /*! + * \brief clone TODO + * \return + */ AutoPtr clone() const; private: + /*! + * \brief clone TODO + * \return + */ virtual Adjust* clone_() const; int adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, @@ -247,7 +267,11 @@ namespace Action { public: virtual ~Erase(); virtual int run(const std::string& path); - typedef std::auto_ptr AutoPtr; + typedef std::auto_ptr AutoPtr; //!< TODO + /*! + * \brief clone TODO + * \return + */ AutoPtr clone() const; /*! @@ -272,8 +296,12 @@ namespace Action { int eraseXmpData(Exiv2::Image* image) const; private: + /*! + * \brief clone TODO + * \return + */ virtual Erase* clone_() const; - std::string path_; + std::string path_; //!< TODO }; // class Erase @@ -284,7 +312,11 @@ namespace Action { public: virtual ~Extract(); virtual int run(const std::string& path); - typedef std::auto_ptr AutoPtr; + typedef std::auto_ptr AutoPtr; //!< TODO + /*! + * \brief clone TODO + * \return + */ AutoPtr clone() const; /*! @@ -307,8 +339,12 @@ namespace Action { void writePreviewFile(const Exiv2::PreviewImage& pvImg, int num) const; private: + /*! + * \brief clone TODO + * \return + */ virtual Extract* clone_() const; - std::string path_; + std::string path_; //!< TODO }; // class Extract @@ -319,7 +355,11 @@ namespace Action { public: virtual ~Insert(); virtual int run(const std::string& path); - typedef std::auto_ptr AutoPtr; + typedef std::auto_ptr AutoPtr; //!< TODO + /*! + * \brief clone TODO + * \return + */ AutoPtr clone() const; /*! @@ -348,7 +388,11 @@ namespace Action { public: virtual ~Modify(); virtual int run(const std::string& path); - typedef std::auto_ptr AutoPtr; + typedef std::auto_ptr AutoPtr; //!< TODO + /*! + * \brief clone TODO + * \return + */ AutoPtr clone() const; Modify() {} //! Apply modification commands to the \em pImage, return 0 if successful. @@ -381,12 +425,20 @@ namespace Action { public: virtual ~FixIso(); virtual int run(const std::string& path); - typedef std::auto_ptr AutoPtr; + typedef std::auto_ptr AutoPtr; //!< TODO + /*! + * \brief clone TODO + * \return + */ AutoPtr clone() const; private: + /*! + * \brief clone TODO + * \return + */ virtual FixIso* clone_() const; - std::string path_; + std::string path_; //!< TODO }; // class FixIso @@ -399,12 +451,20 @@ namespace Action { public: virtual ~FixCom(); virtual int run(const std::string& path); - typedef std::auto_ptr AutoPtr; + typedef std::auto_ptr AutoPtr; //!< TODO + /*! + * \brief clone TODO + * \return + */ AutoPtr clone() const; private: + /*! + * \brief clone TODO + * \return + */ virtual FixCom* clone_() const; - std::string path_; + std::string path_; //!< TODO }; // class FixCom diff --git a/src/asfvideo.cpp b/src/asfvideo.cpp index e296a0be..29e14ded 100644 --- a/src/asfvideo.cpp +++ b/src/asfvideo.cpp @@ -160,6 +160,7 @@ namespace Exiv2 { { 0x7A22, "GSM-AMR (VBR including SID)" } }; + //! File properties. extern const TagDetails filePropertiesTags[] = { { 7, "Xmp.video.FileLength" }, { 6, "Xmp.video.CreationDate" }, @@ -170,6 +171,7 @@ namespace Exiv2 { { 1, "Xmp.video.MaxBitRate" } }; + //!Contents Description. extern const TagDetails contentDescriptionTags[] = { { 0, "Xmp.video.Title" }, { 1, "Xmp.video.Author" }, @@ -293,11 +295,37 @@ namespace Exiv2 { using namespace Exiv2::Internal; + class AsfVideo::Private + { + public: + Private() + { + continueTraversing_ = true; + localPosition_ = 1; + streamNumber_ = 0; + height_ = 1; + width_ = 1; + } + //! Variable to check the end of metadata traversing. + bool continueTraversing_; + //! Variable which stores current position of the read pointer. + uint64_t localPosition_; + //! Variable which stores current stream being processsed. + int streamNumber_; + //! Variable to store height and width of a video frame. + uint64_t height_, width_; + }; + AsfVideo::AsfVideo(BasicIo::AutoPtr io) - : Image(ImageType::asf, mdNone, io) + : Image(ImageType::asf, mdNone, io),d(new Private) { } // AsfVideo::AsfVideo + AsfVideo::~AsfVideo() + { + delete d; + } + std::string AsfVideo::mimeType() const { return "video/asf"; @@ -319,15 +347,15 @@ namespace Exiv2 { IoCloser closer(*io_); clearMetadata(); - continueTraversing_ = true; + d->continueTraversing_ = true; io_->seek(0, BasicIo::beg); - height_ = width_ = 1; + d->height_ = d->width_ = 1; xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576; xmpData_["Xmp.video.FileName"] = io_->path(); xmpData_["Xmp.video.MimeType"] = mimeType(); - while (continueTraversing_) decodeBlock(); + while (d->continueTraversing_) decodeBlock(); aspectRatio(); } // AsfVideo::readMetadata @@ -337,7 +365,6 @@ namespace Exiv2 { const long bufMinSize = 9; DataBuf buf(bufMinSize); unsigned long size = 0; - buf.pData_[8] = '\0' ; const TagVocabulary* tv; uint64_t cur_pos = io_->tell(); @@ -345,7 +372,7 @@ namespace Exiv2 { io_->read(guidBuf, 16); if(io_->eof()) { - continueTraversing_ = false; + d->continueTraversing_ = false; return; } @@ -354,7 +381,6 @@ namespace Exiv2 { getGUID(guidBuf, GUID); tv = find( GUIDReferenceTags, GUID); - std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 8); size = static_cast(getUint64_t(buf)); @@ -364,7 +390,7 @@ namespace Exiv2 { else io_->seek(cur_pos + size, BasicIo::beg); - localPosition_ = io_->tell(); + d->localPosition_ = io_->tell(); } // AsfVideo::decodeBlock void AsfVideo::tagDecoder(const TagVocabulary *tv, uint64_t size) @@ -376,11 +402,11 @@ namespace Exiv2 { Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpSeq); if(compareTag( exvGettext(tv->label_), "Header")) { - localPosition_ = 0; + d->localPosition_ = 0; io_->read(buf.pData_, 4); io_->read(buf.pData_, 2); - while(localPosition_ < cur_pos + size) decodeBlock(); + while(d->localPosition_ < cur_pos + size) decodeBlock(); } else if(compareTag( exvGettext(tv->label_), "File_Properties")) @@ -408,7 +434,7 @@ namespace Exiv2 { extendedStreamProperties(size); else if(compareTag( exvGettext(tv->label_), "Header_Extension")) { - localPosition_ = 0; + d->localPosition_ = 0; headerExtension(size); } @@ -428,7 +454,7 @@ namespace Exiv2 { } io_->seek(cur_pos + size, BasicIo::beg); - localPosition_ = io_->tell(); + d->localPosition_ = io_->tell(); } // AsfVideo::tagDecoder void AsfVideo::extendedStreamProperties(uint64_t size) @@ -440,16 +466,16 @@ namespace Exiv2 { std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 2); - streamNumber_ = Exiv2::getUShort(buf.pData_, littleEndian); + d->streamNumber_ = Exiv2::getUShort(buf.pData_, littleEndian); io_->read(buf.pData_, 2); io_->read(buf.pData_, 8); avgTimePerFrame = getUint64_t(buf); - if(previousStream < streamNumber_ && avgTimePerFrame != 0) + if(previousStream < d->streamNumber_ && avgTimePerFrame != 0) xmpData_["Xmp.video.FrameRate"] = (double)10000000/(double)avgTimePerFrame; - previousStream = streamNumber_; + previousStream = d->streamNumber_; io_->seek(cur_pos + size, BasicIo::beg); } // AsfVideo::extendedStreamProperties @@ -466,7 +492,6 @@ namespace Exiv2 { } for (int i = 0 ; i < 5 ; ++i) { DataBuf buf(length[i]); - std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, length[i]); if (io_->error() || io_->eof()) throw Error(14); const TagDetails* td = find(contentDescriptionTags, i); @@ -510,7 +535,7 @@ namespace Exiv2 { io_->read(buf.pData_, 8); std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 1); - streamNumber_ = (int)buf.pData_[0] & 127; + d->streamNumber_ = (int)buf.pData_[0] & 127; io_->read(buf.pData_, 5); std::memset(buf.pData_, 0x0, buf.size_); @@ -519,7 +544,7 @@ namespace Exiv2 { if(stream == 2) { xmpData_["Xmp.video.Width"] = temp; - width_ = temp; + d->width_ = temp; } else if(stream == 1) { xmpData_["Xmp.audio.Codec"] = test->printAudioEncoding(temp); @@ -535,7 +560,7 @@ namespace Exiv2 { if(stream == 2) { xmpData_["Xmp.video.Height"] = temp; - height_ = temp; + d->height_ = temp; } else if(stream == 1) { xmpData_["Xmp.audio.SampleRate"] = temp; @@ -615,7 +640,7 @@ namespace Exiv2 { buf.pData_[4] = '\0' ; io_->read(buf.pData_, 4); - while(localPosition_ < cur_pos + size) decodeBlock(); + while(d->localPosition_ < cur_pos + size) decodeBlock(); io_->seek(cur_pos + size, BasicIo::beg); } // AsfVideo::headerExtension @@ -768,7 +793,7 @@ namespace Exiv2 { { //TODO - Make a better unified method to handle all cases of Aspect Ratio - double aspectRatio = (double)width_ / (double)height_; + double aspectRatio = (double)d->width_ / (double)d->height_; aspectRatio = floor(aspectRatio*10) / 10; xmpData_["Xmp.video.AspectRatio"] = aspectRatio; diff --git a/src/asfvideo.hpp b/src/asfvideo.hpp index 79515b9c..32ea14ce 100644 --- a/src/asfvideo.hpp +++ b/src/asfvideo.hpp @@ -69,6 +69,7 @@ namespace Exiv2 { method to get a temporary reference. */ AsfVideo(BasicIo::AutoPtr io); + ~AsfVideo(); //@} //! @name Manipulators @@ -154,14 +155,9 @@ namespace Exiv2 { //@} private: - //! Variable to check the end of metadata traversing. - bool continueTraversing_; - //! Variable which stores current position of the read pointer. - uint64_t localPosition_; - //! Variable which stores current stream being processsed. - int streamNumber_; - //! Variable to store height and width of a video frame. - uint64_t height_, width_; + + class Private; + Private * const d; }; //Class AsfVideo diff --git a/src/error.hpp b/src/error.hpp index b8df55d2..58686421 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -274,6 +274,11 @@ namespace Exiv2 { } template template + /*! + * \brief BasicError::BasicError TODO + * \param code + * \param arg1 + */ BasicError::BasicError(int code, const A& arg1) : code_(code), count_(1), arg1_(toBasicString(arg1)) { @@ -281,6 +286,12 @@ namespace Exiv2 { } template template + /*! + * \brief BasicError::BasicError TODO + * \param code + * \param arg1 + * \param arg2 + */ BasicError::BasicError(int code, const A& arg1, const B& arg2) : code_(code), count_(2), arg1_(toBasicString(arg1)), @@ -290,6 +301,13 @@ namespace Exiv2 { } template template + /*! + * \brief BasicError::BasicError TODO + * \param code + * \param arg1 + * \param arg2 + * \param arg3 + */ BasicError::BasicError(int code, const A& arg1, const B& arg2, const C& arg3) : code_(code), count_(3), arg1_(toBasicString(arg1)), diff --git a/src/image.cpp b/src/image.cpp index bedad72a..14538366 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -131,8 +131,8 @@ namespace { { ImageType::tga, newTgaInstance, isTgaType, amNone, amNone, amNone, amNone }, { ImageType::bmp, newBmpInstance, isBmpType, amNone, amNone, amNone, amNone }, { ImageType::jp2, newJp2Instance, isJp2Type, amReadWrite, amReadWrite, amReadWrite, amNone }, - { ImageType::qtime,newQTimeInstance,isQTimeType,amRead, amNone, amRead, amNone }, - { ImageType::riff, newRiffInstance, isRiffType, amRead, amNone, amRead, amNone }, + { ImageType::qtime,newQTimeInstance,isQTimeType,amRead, amNone, amReadWrite, amNone }, + { ImageType::riff, newRiffInstance, isRiffType, amRead, amNone, amReadWrite, amNone }, { ImageType::asf, newAsfInstance, isAsfType, amNone, amNone, amRead, amNone }, { ImageType::mkv, newMkvInstance, isMkvType, amNone, amNone, amRead, amNone }, // End of list marker diff --git a/src/matroskavideo.cpp b/src/matroskavideo.cpp index 78d335c1..9b726667 100644 --- a/src/matroskavideo.cpp +++ b/src/matroskavideo.cpp @@ -36,43 +36,49 @@ EXIV2_RCSID("@(#) $Id$") #include "basicio.hpp" #include "tags.hpp" #include "tags_int.hpp" - +#include "types.hpp" +#include "tiffimage_int.hpp" // + standard includes #include #include +#define lengthof(x) (sizeof(x)/sizeof(x[0])) + +using namespace std; // ***************************************************************************** // class member definitions -namespace Exiv2 { - namespace Internal { +namespace Exiv2 +{ +namespace Internal +{ - //! List of composite tags. They are skipped and the child tags are read immediately - uint64_t compositeTagsList[] = { - 0x0000, 0x000e, 0x000f, 0x0020, 0x0026, 0x002e, 0x0036, - 0x0037, 0x003b, 0x005b, 0x0060, 0x0061, 0x0068, 0x05b9, - 0x0dbb, 0x1034, 0x1035, 0x1854, 0x21a7, 0x2240, 0x23c0, - 0x2624, 0x27c8, 0x2911, 0x2924, 0x2944, 0x2d80, 0x3373, - 0x35a1, 0x3e5b, 0x3e7b, - 0x14d9b74, 0x254c367, 0x549a966, 0x654ae6b, 0x8538067, - 0x941a469, 0xa45dfa3, 0xb538667, 0xc53bb6b, 0xf43b675 - }; +//! List of composite tags. They are skipped and the child tags are read immediately +uint64_t compositeTagsList[] ={ + 0x0000, 0x000e, 0x000f, 0x0020, 0x0026, 0x002e, 0x0036, + 0x0037, 0x003b, 0x005b, 0x0060, 0x0061, 0x0068, 0x05b9, + 0x0dbb, 0x1034, 0x1035, 0x1854, 0x21a7, 0x2240, 0x23c0, + 0x2624, 0x27c8, 0x2911, 0x2924, 0x2944, 0x2d80, 0x3373, + 0x35a1, 0x3e5b, 0x3e7b, + 0x14d9b74, 0x254c367, 0x549a966, 0x654ae6b, 0x8538067, + 0x941a469, 0xa45dfa3, 0xb538667, 0xc53bb6b, 0xf43b675 +}; - //! List of tags which are ignored, i.e., tag and value won't be read - uint64_t ignoredTagsList[] = { - 0x0021, 0x0023, 0x0033, 0x0071, 0x0077, 0x006c, 0x0067, 0x007b, 0x02f2, 0x02f3, - 0x1031, 0x1032, 0x13ab, 0x13ac, 0x15ee, 0x23a2, 0x23c6, 0x2e67, 0x33a4, 0x33c5, - 0x3446, 0x2de7, 0x2df8, 0x26bf, 0x28ca, 0x3384, 0x13b8, 0x037e, 0x0485, 0x18d7, - 0x0005, 0x0009, 0x0011, 0x0012, 0x0016, 0x0017, 0x0018, 0x0022, 0x0024, 0x0025, - 0x0027, 0x002b, 0x002f, 0x003f, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x006a, - 0x006b, 0x006e, 0x007a, 0x007d, 0x0255, 0x3eb5, 0x3ea5, 0x3d7b, 0x33c4, 0x2fab, - 0x2ebc, 0x29fc, 0x29a5, 0x2955, 0x2933, 0x135f, 0x2922, 0x26a5, 0x26fc, 0x2532, - 0x23c9, 0x23c4, 0x23c5, 0x137f, 0x1378, 0x07e2, 0x07e3, 0x07e4, 0x0675, 0x05bc, - 0x05bd, 0x05db, 0x05dd, 0x0598, 0x050d, 0x0444, 0x037c, +//! List of tags which are ignored, i.e., tag and value won't be read +uint64_t ignoredTagsList[] ={ + 0x0021, 0x0023, 0x0033, 0x0071, 0x0077, 0x006c, 0x0067, 0x007b, 0x02f2, 0x02f3, + 0x1031, 0x1032, 0x13ab, 0x13ac, 0x15ee, 0x23a2, 0x23c6, 0x2e67, 0x33a4, 0x33c5, + 0x3446, 0x2de7, 0x2df8, 0x26bf, 0x28ca, 0x3384, 0x13b8, 0x037e, 0x0485, 0x18d7, + 0x0005, 0x0009, 0x0011, 0x0012, 0x0016, 0x0017, 0x0018, 0x0022, 0x0024, 0x0025, + 0x0027, 0x002b, 0x002f, 0x003f, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x006a, + 0x006b, 0x006e, 0x007a, 0x007d, 0x0255, 0x3eb5, 0x3ea5, 0x3d7b, 0x33c4, 0x2fab, + 0x2ebc, 0x29fc, 0x29a5, 0x2955, 0x2933, 0x135f, 0x2922, 0x26a5, 0x26fc, 0x2532, + 0x23c9, 0x23c4, 0x23c5, 0x137f, 0x1378, 0x07e2, 0x07e3, 0x07e4, 0x0675, 0x05bc, + 0x05bd, 0x05db, 0x05dd, 0x0598, 0x050d, 0x0444, 0x037c, - 0x3314f, 0x43a770, 0x1eb923, 0x1cb923, 0xeb524, 0x1c83ab, 0x1e83bb - }; + 0x3314f, 0x43a770, 0x1eb923, 0x1cb923, 0xeb524, 0x1c83ab, 0x1e83bb +}; - /*! +/*! Tag Look-up list for Matroska Type Video Files The Tags have been categorized in 4 categories. Which are mentioned as a comment in front of them. @@ -81,682 +87,913 @@ namespace Exiv2 { u -- Tag used directly for storing metadata ui -- Tag used only internally */ - extern const MatroskaTags matroskaTags[] = { - { 0x0000, "ChapterDisplay" }, //s - { 0x0003, "TrackType" }, //ui - { 0x0005, "ChapterString" }, //sd - { 0x0006, "VideoCodecID/AudioCodecID/CodecID" }, //ui - { 0x0008, "TrackDefault" }, //ui - { 0x0009, "ChapterTrackNumber" }, //sd - { 0x000e, "Slices" }, //s - { 0x000f, "ChapterTrack" }, //s - { 0x0011, "ChapterTimeStart" }, //sd - { 0x0012, "ChapterTimeEnd" }, //sd - { 0x0016, "CueRefTime" }, //sd - { 0x0017, "CueRefCluster" }, //sd - { 0x0018, "ChapterFlagHidden" }, //sd - { 0x001a, "Xmp.video.VideoScanTpye" }, //u - { 0x001b, "BlockDuration" }, //s - { 0x001c, "TrackLacing" }, //ui - { 0x001f, "Xmp.audio.ChannelType" }, //u - { 0x0020, "BlockGroup" }, //s - { 0x0021, "Block" }, //sd - { 0x0022, "BlockVirtual" }, //sd - { 0x0023, "SimpleBlock" }, //sd - { 0x0024, "CodecState" }, //sd - { 0x0025, "BlockAdditional" }, //sd - { 0x0026, "BlockMore" }, //s - { 0x0027, "Position" }, //sd - { 0x002a, "CodecDecodeAll" }, //ui - { 0x002b, "PrevSize" }, //sd - { 0x002e, "TrackEntry" }, //s - { 0x002f, "EncryptedBlock" }, //sd - { 0x0030, "Xmp.video.Width" }, //u - { 0x0033, "CueTime" }, //sd - { 0x0035, "Xmp.audio.SampleRate" }, //u - { 0x0036, "ChapterAtom" }, //s - { 0x0037, "CueTrackPositions" }, //s - { 0x0039, "TrackUsed" }, //ui - { 0x003a, "Xmp.video.Height" }, //u - { 0x003b, "CuePoint" }, //s - { 0x003f, "CRC-32" }, //sd - { 0x004b, "BlockAdditionalID" }, //sd - { 0x004c, "LaceNumber" }, //sd - { 0x004d, "FrameNumber" }, //sd - { 0x004e, "Delay" }, //sd - { 0x004f, "ClusterDuration" }, //sd - { 0x0057, "TrackNumber" }, //ui - { 0x005b, "CueReference" }, //s - { 0x0060, "Video" }, //s - { 0x0061, "Audio" }, //s - { 0x0067, "Timecode" }, //sd - { 0x0068, "TimeSlice" }, //s - { 0x006a, "CueCodecState" }, //sd - { 0x006b, "CueRefCodecState" }, //sd - { 0x006c, "Void" }, //sd - { 0x006e, "BlockAddID" }, //sd - { 0x0071, "CueClusterPosition" }, //sd - { 0x0077, "CueTrack" }, //sd - { 0x007a, "ReferencePriority" }, //sd - { 0x007b, "ReferenceBlock" }, //sd - { 0x007d, "ReferenceVirtual" }, //sd - { 0x0254, "Xmp.video.ContentCompressAlgo" }, //u - { 0x0255, "ContentCompressionSettings" }, //sd - { 0x0282, "Xmp.video.DocType" }, //u - { 0x0285, "Xmp.video.DocTypeReadVersion" }, //u - { 0x0286, "Xmp.video.EBMLVersion" }, //u - { 0x0287, "Xmp.video.DocTypeVersion" }, //u - { 0x02f2, "EBMLMaxIDLength" }, //sd - { 0x02f3, "EBMLMaxSizeLength" }, //sd - { 0x02f7, "Xmp.video.EBMLReadVersion" }, //u - { 0x037c, "ChapterLanguage" }, //sd - { 0x037e, "ChapterCountry" }, //sd - { 0x0444, "SegmentFamily" }, //sd - { 0x0461, "Xmp.video.DateUTC" }, //Date Time Original - measured in seconds relatively to Jan 01, 2001, 0:00:00 GMT+0h - { 0x047a, "Xmp.video.TagLanguage" }, //u - { 0x0484, "Xmp.video.TagDefault" }, //u - { 0x0485, "TagBinary" }, //sd - { 0x0487, "Xmp.video.TagString" }, //u - { 0x0489, "Xmp.video.Duration" }, //u - { 0x050d, "ChapterProcessPrivate" }, //sd - { 0x0598, "ChapterFlagEnabled" }, //sd - { 0x05a3, "Xmp.video.TagName" }, //u - { 0x05b9, "EditionEntry" }, //s - { 0x05bc, "EditionUID" }, //sd - { 0x05bd, "EditionFlagHidden" }, //sd - { 0x05db, "EditionFlagDefault" }, //sd - { 0x05dd, "EditionFlagOrdered" }, //sd - { 0x065c, "Xmp.video.AttachFileData" }, //u - { 0x0660, "Xmp.video.AttachFileMIME" }, //u - { 0x066e, "Xmp.video.AttachFileName" }, //u - { 0x0675, "AttachedFileReferral" }, //sd - { 0x067e, "Xmp.video.AttachFileDesc" }, //u - { 0x06ae, "Xmp.video.AttachFileUID" }, //u - { 0x07e1, "Xmp.video.ContentEncryptAlgo" }, //u - { 0x07e2, "ContentEncryptionKeyID" }, //sd - { 0x07e3, "ContentSignature" }, //sd - { 0x07e4, "ContentSignatureKeyID" }, //sd - { 0x07e5, "Xmp.video.ContentSignAlgo" }, //u - { 0x07e6, "Xmp.video.ContentSignHashAlgo" }, //u - { 0x0d80, "Xmp.video.MuxingApp" }, //u - { 0x0dbb, "Seek" }, //s - { 0x1031, "ContentEncodingOrder" }, //sd - { 0x1032, "ContentEncodingScope" }, //sd - { 0x1033, "Xmp.video.ContentEncodingType" }, //u - { 0x1034, "ContentCompression" }, //s - { 0x1035, "ContentEncryption" }, //s - { 0x135f, "CueRefNumber" }, //sd - { 0x136e, "Xmp.video.TrackName" }, //u - { 0x1378, "CueBlockNumber" }, //sd - { 0x137f, "TrackOffset" }, //sd - { 0x13ab, "SeekID" }, //sd - { 0x13ac, "SeekPosition" }, //sd - { 0x13b8, "Stereo3DMode" }, //sd - { 0x14aa, "Xmp.video.CropBottom" }, //ui - { 0x14b0, "Xmp.video.Width" }, //u - { 0x14b2, "Xmp.video.DisplayUnit" }, //u - { 0x14b3, "Xmp.video.AspectRatioType" }, //u - { 0x14ba, "Xmp.video.Height" }, //u - { 0x14bb, "Xmp.video.CropTop" }, //ui - { 0x14cc, "Xmp.video.CropLeft" }, //ui - { 0x14dd, "Xmp.video.CropRight" }, //ui - { 0x15aa, "TrackForced" }, //ui - { 0x15ee, "MaxBlockAdditionID" }, //sd - { 0x1741, "Xmp.video.WritingApp" }, //u - { 0x1854, "SilentTracks" }, //s - { 0x18d7, "SilentTrackNumber" }, //sd - { 0x21a7, "AttachedFile" }, //s - { 0x2240, "ContentEncoding" }, //s - { 0x2264, "Xmp.audio.BitsPerSample" }, //u - { 0x23a2, "CodecPrivate" }, //sd - { 0x23c0, "Targets" }, //s - { 0x23c3, "Xmp.video.PhysicalEquivalent" }, //u - { 0x23c4, "TagChapterUID" }, //sd - { 0x23c5, "TagTrackUID" }, //sd - { 0x23c6, "TagAttachmentUID" }, //sd - { 0x23c9, "TagEditionUID" }, //sd - { 0x23ca, "Xmp.video.TargetType" }, //u - { 0x2532, "SignedElement" }, //sd - { 0x2624, "TrackTranslate" }, //s - { 0x26a5, "TrackTranslateTrackID" }, //sd - { 0x26bf, "TrackTranslateCodec" }, //sd - { 0x26fc, "TrackTranslateEditionUID" }, //sd - { 0x27c8, "SimpleTag" }, //s - { 0x28ca, "TargetTypeValue" }, //sd - { 0x2911, "ChapterProcessCommand" }, //s - { 0x2922, "ChapterProcessTime" }, //sd - { 0x2924, "ChapterTranslate" }, //s - { 0x2933, "ChapterProcessData" }, //sd - { 0x2944, "ChapterProcess" }, //s - { 0x2955, "ChapterProcessCodecID" }, //sd - { 0x29a5, "ChapterTranslateID" }, //sd - { 0x29bf, "Xmp.video.TranslateCodec" }, //u - { 0x29fc, "ChapterTranslateEditionUID" }, //sd - { 0x2d80, "ContentEncodings" }, //s - { 0x2de7, "MinCache" }, //sd - { 0x2df8, "MaxCache" }, //sd - { 0x2e67, "ChapterSegmentUID" }, //sd - { 0x2ebc, "ChapterSegmentEditionUID" }, //sd - { 0x2fab, "TrackOverlay" }, //sd - { 0x3373, "Tag" }, //s - { 0x3384, "SegmentFileName" }, //sd - { 0x33a4, "SegmentUID" }, //sd - { 0x33c4, "ChapterUID" }, //sd - { 0x33c5, "TrackUID" }, //sd - { 0x3446, "TrackAttachmentUID" }, //sd - { 0x35a1, "BlockAdditions" }, //s - { 0x38b5, "Xmp.audio.OutputSampleRate" }, //u - { 0x3ba9, "Xmp.video.Title" }, //u - { 0x3d7b, "ChannelPositions" }, //sd - { 0x3e5b, "SignatureElements" }, //s - { 0x3e7b, "SignatureElementList" }, //s - { 0x3e8a, "Xmp.video.ContentSignAlgo" }, //u - { 0x3e9a, "Xmp.video.ContentSignHashAlgo" }, //u - { 0x3ea5, "SignaturePublicKey" }, //sd - { 0x3eb5, "Signature" }, //sd - { 0x2b59c, "TrackLanguage" }, //ui - { 0x3314f, "TrackTimecodeScale" }, //sd - { 0x383e3, "Xmp.video.FrameRate" }, //u - { 0x3e383, "VideoFrameRate/DefaultDuration" }, //ui - { 0x58688, "VideoCodecName/AudioCodecName/CodecName" }, //ui - { 0x6b240, "CodecDownloadURL" }, //ui - { 0xad7b1, "TimecodeScale" }, //ui - { 0xeb524, "ColorSpace" }, //sd - { 0xfb523, "Xmp.video.OpColor" }, //u - { 0x1a9697, "CodecSettings" }, //ui - { 0x1b4040, "CodecInfoURL" }, //ui - { 0x1c83ab, "PrevFileName" }, //sd - { 0x1cb923, "PrevUID" }, //sd - { 0x1e83bb, "NextFileName" }, //sd - { 0x1eb923, "NextUID" }, //sd - { 0x43a770, "Chapters" }, //sd - { 0x14d9b74, "SeekHead" }, //s - { 0x254c367, "Tags" }, //s - { 0x549a966, "Info" }, //s - { 0x654ae6b, "Tracks" }, //s - { 0x8538067, "SegmentHeader" }, //s - { 0x941a469, "Attachments" }, //s - { 0xa45dfa3, "EBMLHeader" }, //s - { 0xb538667, "SignatureSlot" }, //s - { 0xc53bb6b, "Cues" }, //s - { 0xf43b675, "Cluster" }, //s - }; +extern const MatroskaTags matroskaTags[] ={ + { 0x0000, "ChapterDisplay" }, //s + { 0x0003, "TrackType" }, //ui + { 0x0005, "ChapterString" }, //sd + { 0x0006, "VideoCodecID/AudioCodecID/CodecID" }, //ui + { 0x0008, "TrackDefault" }, //ui + { 0x0009, "ChapterTrackNumber" }, //sd + { 0x000e, "Slices" }, //s + { 0x000f, "ChapterTrack" }, //s + { 0x0011, "ChapterTimeStart" }, //sd + { 0x0012, "ChapterTimeEnd" }, //sd + { 0x0016, "CueRefTime" }, //sd + { 0x0017, "CueRefCluster" }, //sd + { 0x0018, "ChapterFlagHidden" }, //sd + { 0x001a, "Xmp.video.VideoScanTpye" }, //u + { 0x001b, "BlockDuration" }, //s + { 0x001c, "TrackLacing" }, //ui + { 0x001f, "Xmp.audio.ChannelType" }, //u + { 0x0020, "BlockGroup" }, //s + { 0x0021, "Block" }, //sd + { 0x0022, "BlockVirtual" }, //sd + { 0x0023, "SimpleBlock" }, //sd + { 0x0024, "CodecState" }, //sd + { 0x0025, "BlockAdditional" }, //sd + { 0x0026, "BlockMore" }, //s + { 0x0027, "Position" }, //sd + { 0x002a, "CodecDecodeAll" }, //ui + { 0x002b, "PrevSize" }, //sd + { 0x002e, "TrackEntry" }, //s + { 0x002f, "EncryptedBlock" }, //sd + { 0x0030, "Xmp.video.Width" }, //u + { 0x0033, "CueTime" }, //sd + { 0x0035, "Xmp.audio.SampleRate" }, //u + { 0x0036, "ChapterAtom" }, //s + { 0x0037, "CueTrackPositions" }, //s + { 0x0039, "TrackUsed" }, //ui + { 0x003a, "Xmp.video.Height" }, //u + { 0x003b, "CuePoint" }, //s + { 0x003f, "CRC-32" }, //sd + { 0x004b, "BlockAdditionalID" }, //sd + { 0x004c, "LaceNumber" }, //sd + { 0x004d, "FrameNumber" }, //sd + { 0x004e, "Delay" }, //sd + { 0x004f, "ClusterDuration" }, //sd + { 0x0057, "TrackNumber" }, //ui + { 0x005b, "CueReference" }, //s + { 0x0060, "Video" }, //s + { 0x0061, "Audio" }, //s + { 0x0067, "Timecode" }, //sd + { 0x0068, "TimeSlice" }, //s + { 0x006a, "CueCodecState" }, //sd + { 0x006b, "CueRefCodecState" }, //sd + { 0x006c, "Void" }, //sd + { 0x006e, "BlockAddID" }, //sd + { 0x0071, "CueClusterPosition" }, //sd + { 0x0077, "CueTrack" }, //sd + { 0x007a, "ReferencePriority" }, //sd + { 0x007b, "ReferenceBlock" }, //sd + { 0x007d, "ReferenceVirtual" }, //sd + { 0x0254, "Xmp.video.ContentCompressAlgo" }, //u + { 0x0255, "ContentCompressionSettings" }, //sd + { 0x0282, "Xmp.video.DocType" }, //u + { 0x0285, "Xmp.video.DocTypeReadVersion" }, //u + { 0x0286, "Xmp.video.EBMLVersion" }, //u + { 0x0287, "Xmp.video.DocTypeVersion" }, //u + { 0x02f2, "EBMLMaxIDLength" }, //sd + { 0x02f3, "EBMLMaxSizeLength" }, //sd + { 0x02f7, "Xmp.video.EBMLReadVersion" }, //u + { 0x037c, "ChapterLanguage" }, //sd + { 0x037e, "ChapterCountry" }, //sd + { 0x0444, "SegmentFamily" }, //sd + { 0x0461, "Xmp.video.DateUTC" }, //Date Time Original - measured in seconds relatively to Jan 01, 2001, 0:00:00 GMT+0h + { 0x047a, "Xmp.video.TagLanguage" }, //u + { 0x0484, "Xmp.video.TagDefault" }, //u + { 0x0485, "TagBinary" }, //sd + { 0x0487, "Xmp.video.TagString" }, //u + { 0x0489, "Xmp.video.Duration" }, //u + { 0x050d, "ChapterProcessPrivate" }, //sd + { 0x0598, "ChapterFlagEnabled" }, //sd + { 0x05a3, "Xmp.video.TagName" }, //u + { 0x05b9, "EditionEntry" }, //s + { 0x05bc, "EditionUID" }, //sd + { 0x05bd, "EditionFlagHidden" }, //sd + { 0x05db, "EditionFlagDefault" }, //sd + { 0x05dd, "EditionFlagOrdered" }, //sd + { 0x065c, "Xmp.video.AttachFileData" }, //u + { 0x0660, "Xmp.video.AttachFileMIME" }, //u + { 0x066e, "Xmp.video.AttachFileName" }, //u + { 0x0675, "AttachedFileReferral" }, //sd + { 0x067e, "Xmp.video.AttachFileDesc" }, //u + { 0x06ae, "Xmp.video.AttachFileUID" }, //u + { 0x07e1, "Xmp.video.ContentEncryptAlgo" }, //u + { 0x07e2, "ContentEncryptionKeyID" }, //sd + { 0x07e3, "ContentSignature" }, //sd + { 0x07e4, "ContentSignatureKeyID" }, //sd + { 0x07e5, "Xmp.video.ContentSignAlgo" }, //u + { 0x07e6, "Xmp.video.ContentSignHashAlgo" }, //u + { 0x0d80, "Xmp.video.MuxingApp" }, //u + { 0x0dbb, "Seek" }, //s + { 0x1031, "ContentEncodingOrder" }, //sd + { 0x1032, "ContentEncodingScope" }, //sd + { 0x1033, "Xmp.video.ContentEncodingType" }, //u + { 0x1034, "ContentCompression" }, //s + { 0x1035, "ContentEncryption" }, //s + { 0x135f, "CueRefNumber" }, //sd + { 0x136e, "Xmp.video.TrackName" }, //u + { 0x1378, "CueBlockNumber" }, //sd + { 0x137f, "TrackOffset" }, //sd + { 0x13ab, "SeekID" }, //sd + { 0x13ac, "SeekPosition" }, //sd + { 0x13b8, "Stereo3DMode" }, //sd + { 0x14aa, "Xmp.video.CropBottom" }, //ui + { 0x14b0, "Xmp.video.Width" }, //u + { 0x14b2, "Xmp.video.DisplayUnit" }, //u + { 0x14b3, "Xmp.video.AspectRatioType" }, //u + { 0x14ba, "Xmp.video.Height" }, //u + { 0x14bb, "Xmp.video.CropTop" }, //ui + { 0x14cc, "Xmp.video.CropLeft" }, //ui + { 0x14dd, "Xmp.video.CropRight" }, //ui + { 0x15aa, "TrackForced" }, //ui + { 0x15ee, "MaxBlockAdditionID" }, //sd + { 0x1741, "Xmp.video.WritingApp" }, //u + { 0x1854, "SilentTracks" }, //s + { 0x18d7, "SilentTrackNumber" }, //sd + { 0x21a7, "AttachedFile" }, //s + { 0x2240, "ContentEncoding" }, //s + { 0x2264, "Xmp.audio.BitsPerSample" }, //u + { 0x23a2, "CodecPrivate" }, //sd + { 0x23c0, "Targets" }, //s + { 0x23c3, "Xmp.video.PhysicalEquivalent" }, //u + { 0x23c4, "TagChapterUID" }, //sd + { 0x23c5, "TagTrackUID" }, //sd + { 0x23c6, "TagAttachmentUID" }, //sd + { 0x23c9, "TagEditionUID" }, //sd + { 0x23ca, "Xmp.video.TargetType" }, //u + { 0x2532, "SignedElement" }, //sd + { 0x2624, "TrackTranslate" }, //s + { 0x26a5, "TrackTranslateTrackID" }, //sd + { 0x26bf, "TrackTranslateCodec" }, //sd + { 0x26fc, "TrackTranslateEditionUID" }, //sd + { 0x27c8, "SimpleTag" }, //s + { 0x28ca, "TargetTypeValue" }, //sd + { 0x2911, "ChapterProcessCommand" }, //s + { 0x2922, "ChapterProcessTime" }, //sd + { 0x2924, "ChapterTranslate" }, //s + { 0x2933, "ChapterProcessData" }, //sd + { 0x2944, "ChapterProcess" }, //s + { 0x2955, "ChapterProcessCodecID" }, //sd + { 0x29a5, "ChapterTranslateID" }, //sd + { 0x29bf, "Xmp.video.TranslateCodec" }, //u + { 0x29fc, "ChapterTranslateEditionUID" }, //sd + { 0x2d80, "ContentEncodings" }, //s + { 0x2de7, "MinCache" }, //sd + { 0x2df8, "MaxCache" }, //sd + { 0x2e67, "ChapterSegmentUID" }, //sd + { 0x2ebc, "ChapterSegmentEditionUID" }, //sd + { 0x2fab, "TrackOverlay" }, //sd + { 0x3373, "Tag" }, //s + { 0x3384, "SegmentFileName" }, //sd + { 0x33a4, "SegmentUID" }, //sd + { 0x33c4, "ChapterUID" }, //sd + { 0x33c5, "TrackUID" }, //sd + { 0x3446, "TrackAttachmentUID" }, //sd + { 0x35a1, "BlockAdditions" }, //s + { 0x38b5, "Xmp.audio.OutputSampleRate" }, //u + { 0x3ba9, "Xmp.video.Title" }, //u + { 0x3d7b, "ChannelPositions" }, //sd + { 0x3e5b, "SignatureElements" }, //s + { 0x3e7b, "SignatureElementList" }, //s + { 0x3e8a, "Xmp.video.ContentSignAlgo" }, //u + { 0x3e9a, "Xmp.video.ContentSignHashAlgo" }, //u + { 0x3ea5, "SignaturePublicKey" }, //sd + { 0x3eb5, "Signature" }, //sd + { 0x2b59c, "TrackLanguage" }, //ui + { 0x3314f, "TrackTimecodeScale" }, //sd + { 0x383e3, "Xmp.video.FrameRate" }, //u + { 0x3e383, "VideoFrameRate/DefaultDuration" }, //ui + { 0x58688, "VideoCodecName/AudioCodecName/CodecName" }, //ui + { 0x6b240, "CodecDownloadURL" }, //ui + { 0xad7b1, "TimecodeScale" }, //ui + { 0xeb524, "ColorSpace" }, //sd + { 0xfb523, "Xmp.video.OpColor" }, //u + { 0x1a9697, "CodecSettings" }, //ui + { 0x1b4040, "CodecInfoURL" }, //ui + { 0x1c83ab, "PrevFileName" }, //sd + { 0x1cb923, "PrevUID" }, //sd + { 0x1e83bb, "NextFileName" }, //sd + { 0x1eb923, "NextUID" }, //sd + { 0x43a770, "Chapters" }, //sd + { 0x14d9b74, "SeekHead" }, //s + { 0x254c367, "Tags" }, //s + { 0x549a966, "Info" }, //s + { 0x654ae6b, "Tracks" }, //s + { 0x8538067, "SegmentHeader" }, //s + { 0x941a469, "Attachments" }, //s + { 0xa45dfa3, "EBMLHeader" }, //s + { 0xb538667, "SignatureSlot" }, //s + { 0xc53bb6b, "Cues" }, //s + { 0xf43b675, "Cluster" }, //s +}; - extern const MatroskaTags matroskaTrackType[] = { - { 0x1, "Video" }, - { 0x2, "Audio" }, - { 0x3, "Complex" }, - { 0x10, "Logo" }, - { 0x11, "Subtitle" }, - { 0x12, "Buttons" }, - { 0x20, "Control" } - }; +//! Multimedia type. +extern const MatroskaTags matroskaTrackType[] ={ + { 0x1, "Video" }, + { 0x2, "Audio" }, + { 0x3, "Complex" }, + { 0x10, "Logo" }, + { 0x11, "Subtitle" }, + { 0x12, "Buttons" }, + { 0x20, "Control" } +}; - extern const MatroskaTags compressionAlgorithm[] = { - { 0, "zlib " }, - { 1, "bzlib" }, - { 2, "lzo1x" }, - { 3, "Header Stripping" } - }; +//! Algorith information. +extern const MatroskaTags compressionAlgorithm[] ={ + { 0, "zlib " }, + { 1, "bzlib" }, + { 2, "lzo1x" }, + { 3, "Header Stripping" } +}; - extern const MatroskaTags audioChannels[] = { - { 1, "Mono" }, - { 2, "Stereo" }, - { 5, "5.1 Surround Sound" }, - { 7, "7.1 Surround Sound" } - }; +//! Channel Type Information. +extern const MatroskaTags audioChannels[] ={ + { 1, "Mono" }, + { 2, "Stereo" }, + { 5, "5.1 Surround Sound" }, + { 7, "7.1 Surround Sound" } +}; - extern const MatroskaTags displayUnit[] = { - { 0x0, "Pixels" }, - { 0x1, "cm" }, - { 0x2, "inches" } - }; +//! Display Information. +extern const MatroskaTags displayUnit[] ={ + { 0x0, "Pixels" }, + { 0x1, "cm" }, + { 0x2, "inches" } +}; - extern const MatroskaTags encryptionAlgorithm[] = { - { 0, "Not Encrypted" }, - { 1, "DES" }, - { 2, "3DES" }, - { 3, "Twofish" }, - { 4, "Blowfish" }, - { 5, "AES" } - }; +//! Encryption Algorithm. +extern const MatroskaTags encryptionAlgorithm[] ={ + { 0, "Not Encrypted" }, + { 1, "DES" }, + { 2, "3DES" }, + { 3, "Twofish" }, + { 4, "Blowfish" }, + { 5, "AES" } +}; - extern const MatroskaTags chapterPhysicalEquivalent[] = { - { 10, "Index" }, - { 20, "Track" }, - { 30, "Session" }, - { 40, "Layer" }, - { 50, "Side" }, - { 60, "CD / DVD" }, - { 70, "Set / Package" }, - }; +//! Chapter Information. +extern const MatroskaTags chapterPhysicalEquivalent[] ={ + { 10, "Index" }, + { 20, "Track" }, + { 30, "Session" }, + { 40, "Layer" }, + { 50, "Side" }, + { 60, "CD / DVD" }, + { 70, "Set / Package" }, +}; - extern const MatroskaTags encodingType[] = { - { 0, "Compression" }, - { 1, "Encryption" } - }; +//! Encoding Information. +extern const MatroskaTags encodingType[] ={ + { 0, "Compression" }, + { 1, "Encryption" } +}; - extern const MatroskaTags videoScanType[] = { - { 0, "Progressive" }, - { 1, "Interlaced" } - }; +//! VideoScan Information. +extern const MatroskaTags videoScanType[] = +{ + { 0, "Progressive" }, + { 1, "Interlaced" } +}; - extern const MatroskaTags chapterTranslateCodec[] = { - { 0, "Matroska Script" }, - { 1, "DVD Menu" } - }; +//! Chapter related Information. +extern const MatroskaTags chapterTranslateCodec[] ={ + { 0, "Matroska Script" }, + { 1, "DVD Menu" } +}; - extern const MatroskaTags aspectRatioType[] = { - { 0, "Free Resizing" }, - { 1, "Keep Aspect Ratio" }, - { 2, "Fixed" } - }; +//! Aspect Ratio Information. +extern const MatroskaTags aspectRatioType[] ={ + { 0, "Free Resizing" }, + { 1, "Keep Aspect Ratio" }, + { 2, "Fixed" } +}; - extern const MatroskaTags contentSignatureAlgorithm[] = { - { 0, "Not Signed" }, - { 1, "RSA" } - }; +//! Content Signature Information. +extern const MatroskaTags contentSignatureAlgorithm[] ={ + { 0, "Not Signed" }, + { 1, "RSA" } +}; - extern const MatroskaTags contentSignatureHashAlgorithm[] = { - { 0, "Not Signed" }, - { 1, "SHA1-160" }, - { 2, "MD5" } - }; +//! Content SIgnature Hash Information. +extern const MatroskaTags contentSignatureHashAlgorithm[] ={ + { 0, "Not Signed" }, + { 1, "SHA1-160" }, + { 2, "MD5" } +}; - extern const MatroskaTags trackEnable[] = { - { 0x1, "Xmp.video.Enabled" }, - { 0x2, "Xmp.audio.Enabled" }, - { 0x11, "Xmp.video.SubTEnabled" } - }; +//! Track Information. +extern const MatroskaTags trackEnable[] ={ + { 0x1, "Xmp.video.Enabled" }, + { 0x2, "Xmp.audio.Enabled" }, + { 0x11, "Xmp.video.SubTEnabled" } +}; - extern const MatroskaTags defaultOn[] = { - { 0x1, "Xmp.video.DefaultOn" }, - { 0x2, "Xmp.audio.DefaultOn" }, - { 0x11, "Xmp.video.SubTDefaultOn" } - }; +//! Default Action Information. +extern const MatroskaTags defaultOn[] ={ + { 0x1, "Xmp.video.DefaultOn" }, + { 0x2, "Xmp.audio.DefaultOn" }, + { 0x11, "Xmp.video.SubTDefaultOn" } +}; - extern const MatroskaTags trackForced[] = { - { 0x1, "Xmp.video.TrackForced" }, - { 0x2, "Xmp.audio.TrackForced" }, - { 0x11, "Xmp.video.SubTTrackForced" } - }; +//! Track Information. +extern const MatroskaTags trackForced[] ={ + { 0x1, "Xmp.video.TrackForced" }, + { 0x2, "Xmp.audio.TrackForced" }, + { 0x11, "Xmp.video.SubTTrackForced" } +}; - extern const MatroskaTags trackLacing[] = { - { 0x1, "Xmp.video.TrackLacing" }, - { 0x2, "Xmp.audio.TrackLacing" }, - { 0x11, "Xmp.video.SubTTrackLacing" } - }; +//! Track Information. +extern const MatroskaTags trackLacing[] ={ + { 0x1, "Xmp.video.TrackLacing" }, + { 0x2, "Xmp.audio.TrackLacing" }, + { 0x11, "Xmp.video.SubTTrackLacing" } +}; - extern const MatroskaTags codecDecodeAll[] = { - { 0x1, "Xmp.video.CodecDecodeAll" }, - { 0x2, "Xmp.audio.CodecDecodeAll" }, - { 0x11, "Xmp.video.SubTCodecDecodeAll" } - }; +//! Codec Information. +extern const MatroskaTags codecDecodeAll[] ={ + { 0x1, "Xmp.video.CodecDecodeAll" }, + { 0x2, "Xmp.audio.CodecDecodeAll" }, + { 0x11, "Xmp.video.SubTCodecDecodeAll" } +}; - extern const MatroskaTags codecDownloadUrl[] = { - { 0x1, "Xmp.video.CodecDownloadUrl" }, - { 0x2, "Xmp.audio.CodecDownloadUrl" }, - { 0x11, "Xmp.video.SubTCodecDownloadUrl" } - }; +//! Codec Information. +extern const MatroskaTags codecDownloadUrl[] ={ + { 0x1, "Xmp.video.CodecDownloadUrl" }, + { 0x2, "Xmp.audio.CodecDownloadUrl" }, + { 0x11, "Xmp.video.SubTCodecDownloadUrl" } +}; - extern const MatroskaTags codecSettings[] = { - { 0x1, "Xmp.video.CodecSettings" }, - { 0x2, "Xmp.audio.CodecSettings" }, - { 0x11, "Xmp.video.SubTCodecSettings" } - }; +//! Codec Information. +extern const MatroskaTags codecSettings[] ={ + { 0x1, "Xmp.video.CodecSettings" }, + { 0x2, "Xmp.audio.CodecSettings" }, + { 0x11, "Xmp.video.SubTCodecSettings" } +}; - extern const MatroskaTags trackCodec[] = { - { 0x1, "Xmp.video.Codec" }, - { 0x2, "Xmp.audio.Compressor" }, - { 0x11, "Xmp.video.SubTCodec" } - }; +//! Track Information. +extern const MatroskaTags trackCodec[] ={ + { 0x1, "Xmp.video.Codec" }, + { 0x2, "Xmp.audio.Compressor" }, + { 0x11, "Xmp.video.SubTCodec" } +}; - extern const MatroskaTags trackLanguage[] = { - { 0x1, "Xmp.video.TrackLang" }, - { 0x2, "Xmp.audio.TrackLang" }, - { 0x11, "Xmp.video.SubTLang" } - }; +//! Track Language Information. +extern const MatroskaTags trackLanguage[] ={ + { 0x1, "Xmp.video.TrackLang" }, + { 0x2, "Xmp.audio.TrackLang" }, + { 0x11, "Xmp.video.SubTLang" } +}; - extern const MatroskaTags codecInfo[] = { - { 0x1, "Xmp.video.CodecInfo" }, - { 0x2, "Xmp.audio.CodecInfo" }, - { 0x11, "Xmp.video.SubTCodecInfo" } - }; +//! Codec Information. +extern const MatroskaTags codecInfo[] ={ + { 0x1, "Xmp.video.CodecInfo" }, + { 0x2, "Xmp.audio.CodecInfo" }, + { 0x11, "Xmp.video.SubTCodecInfo" } +}; - extern const MatroskaTags streamRate[] = { - { 0x1, "Xmp.video.FrameRate" }, - { 0x2, "Xmp.audio.DefaultDuration" } - }; +//! Stream Rate Information. +extern const MatroskaTags streamRate[] ={ + { 0x1, "Xmp.video.FrameRate" }, + { 0x2, "Xmp.audio.DefaultDuration" } +}; - /*! +/*! + * \brief reverseMatroskaTag reverse the members of a structure + * \param inputMatroskaTag + * \param outputMatroskaTag + * \param size + */ +void reverseMatroskaTag(const MatroskaTags inputMatroskaTag[],RevMatroskaTags outputMatroskaTag[] ,int size){ + for (int64_t i=0; i 0 && size <= 8); +uint64_t returnTagValue(const Exiv2::byte* buf, int32_t size){ + assert(size > 0 && size <= 8); - uint64_t b0 = buf[0] & (0xff >> size); - uint64_t tag = b0 << ((size - 1) * 8); - for (long i = 1; i < size; ++i) { - tag |= static_cast(buf[i]) << ((size - i - 1) * 8); - } + uint64_t b0 = buf[0] & (0xff >> size); + uint64_t tag = b0 << ((size - 1) * 8); + for (int32_t i = 1; i < size; ++i) tag |= static_cast(buf[i]) << ((size - i - 1) * 8); + return tag; +} - return tag; - } - - /*! +/*! @brief Function used to convert buffer data into numerical information, information stored in BigEndian format */ - int64_t returnValue(const byte* buf, long size) - { +int64_t returnValue(const Exiv2::byte* buf, int32_t size){ - int64_t temp = 0; + int64_t temp = 0; + for(int64_t i = size-1; i >= 0; i--) temp = temp + static_cast(buf[i]*(pow(256.0, (double)size-i-1))); + // Todo: remove debug output + // std::cerr << "size = " << size << ", val = " << temp << std::hex << " (0x" << temp << std::dec << ")"; - for(int i = size-1; i >= 0; i--) { - temp = temp + static_cast(buf[i]*(pow(256.0, (double)size-i-1))); - } -// Todo: remove debug output -// std::cerr << "size = " << size << ", val = " << temp << std::hex << " (0x" << temp << std::dec << ")"; + uint64_t ret = 0; + for (int32_t i = 0; i < size; ++i) ret |= static_cast(buf[i]) << ((size - i - 1) * 8); - uint64_t ret = 0; - for (long i = 0; i < size; ++i) { - ret |= static_cast(buf[i]) << ((size - i - 1) * 8); - } + // Todo: remove debug output + // std::cerr << ", ret = " << ret << std::hex << " (0x" << ret << std::dec << ")\n"; -// Todo: remove debug output -// std::cerr << ", ret = " << ret << std::hex << " (0x" << ret << std::dec << ")\n"; + return ret; +} - return ret; +/*! + * \brief returnBuf Return raw byte,ready to be written to the file,from value. + * \param numValue + * \param size size of rawData in number of bytes. + * \return + */ +Exiv2::byte* returnBuf(uint64_t numValue,int32_t size) +{ + Exiv2::byte* retVal; + retVal = (Exiv2::byte* )malloc(size*sizeof(8)); + for (int32_t i = 0; i < size; i++) { + retVal[size-i-1] = (Exiv2::byte)(((uint32_t)numValue)%(uint32_t)256); + numValue = numValue/256; } + return retVal; +} // returnBuf -}} // namespace Internal, Exiv2 +} +} // namespace Internal, Exiv2 -namespace Exiv2 { +namespace Exiv2 +{ - using namespace Exiv2::Internal; +using namespace Exiv2::Internal; - MatroskaVideo::MatroskaVideo(BasicIo::AutoPtr io) - : Image(ImageType::mkv, mdNone, io) +class MatroskaVideo::Private +{ +public: + Private() { - } // MatroskaVideo::MatroskaVideo - - std::string MatroskaVideo::mimeType() const - { - return "video/matroska"; - } - - void MatroskaVideo::writeMetadata() - { - } - - void MatroskaVideo::readMetadata() - { - if (io_->open() != 0) throw Error(9, io_->path(), strError()); - - // Ensure that this is the correct image type - if (!isMkvType(*io_, false)) { - if (io_->error() || io_->eof()) throw Error(14); - throw Error(3, "Matroska"); - } - - IoCloser closer(*io_); - clearMetadata(); continueTraversing_ = true; - height_ = width_ = 1; + height_ = 1; + width_ = 1; + m_modifyMetadata = false; + mtLocation = 1; + } - xmpData_["Xmp.video.FileName"] = io_->path(); - xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576; - xmpData_["Xmp.video.MimeType"] = mimeType(); +public: + //! Variable to check the end of metadata traversing. + bool continueTraversing_; + //! Variable to store height and width of a video frame. + uint64_t height_, width_; + //! Variable to decide whether to modify the metada + bool m_modifyMetadata; + int32_t mtLocation; +}; - while (continueTraversing_) decodeBlock(); +MatroskaVideo::MatroskaVideo(BasicIo::AutoPtr io) + : Image(ImageType::mkv, mdNone, io),d(new Private) +{ +} // MatroskaVideo::MatroskaVideo - aspectRatio(); - } // MatroskaVideo::readMetadata +MatroskaVideo::~MatroskaVideo() +{ + delete d; +} - void MatroskaVideo::decodeBlock() - { - byte buf[8]; - io_->read(buf, 1); +std::string MatroskaVideo::mimeType() const +{ + return "video/matroska"; +} - if(io_->eof()) { - continueTraversing_ = false; - return; - } +void MatroskaVideo::writeMetadata() +{ + if (io_->open() != 0) throw Error(9, io_->path(), strError()); + IoCloser closer(*io_); - uint32_t sz = findBlockSize(buf[0]); // 0-8 - if (sz > 0) io_->read(buf + 1, sz - 1); + doWriteMetadata(); - const MatroskaTags* mt = find(matroskaTags, returnTagValue(buf, sz)); + io_->close(); +} - if(mt->val_ == 0xc53bb6b || mt->val_ == 0xf43b675) { - continueTraversing_ = false; - return; - } +void MatroskaVideo::doWriteMetadata() +{ + if (!io_->isopen()) throw Error(20); + if (!isMkvType(*io_, false)){ + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "Matroska"); + } + d->m_modifyMetadata = true; + d->continueTraversing_ = true; + while (d->continueTraversing_) decodeBlock(); +} - bool skip = find(compositeTagsList, mt->val_) != 0; - bool ignore = find(ignoredTagsList, mt->val_) != 0; +void MatroskaVideo::readMetadata() +{ + if (io_->open() != 0) throw Error(9, io_->path(), strError()); - io_->read(buf, 1); - sz = findBlockSize(buf[0]); // 0-8 + // Ensure that this is the correct image type + if (!isMkvType(*io_, false)){ + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "Matroska"); + } - if (sz > 0) io_->read(buf + 1, sz - 1); - uint64_t size = returnTagValue(buf, sz); + IoCloser closer(*io_); + clearMetadata(); + d->continueTraversing_ = true; + d->height_ = d->width_ = 1; - if (skip && !ignore) return; + xmpData_["Xmp.video.FileName"] = io_->path(); + xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576; + xmpData_["Xmp.video.MimeType"] = mimeType(); - const uint64_t bufMinSize = 200; + while (d->continueTraversing_) decodeBlock(); + + aspectRatio(); +} // MatroskaVideo::readMetadata + +void MatroskaVideo::decodeBlock() +{ + Exiv2::byte buf[8]; + d->mtLocation = io_->tell(); + io_->read(buf, 1); + + if(io_->eof()){ + d->continueTraversing_ = false; + return; + } + + uint32_t sz = findBlockSize(buf[0]); // 0-8 + if (sz > 0) io_->read(buf + 1, sz - 1); + + + const MatroskaTags* mt = find(matroskaTags, returnTagValue(buf, sz)); + + if(mt->val_ == 0xc53bb6b || mt->val_ == 0xf43b675){ + d->continueTraversing_ = false; + return; + } + + bool skip = find(compositeTagsList, mt->val_) != 0; + bool ignore = find(ignoredTagsList, mt->val_) != 0; + + io_->read(buf, 1); + sz = findBlockSize(buf[0]); // 0-8 + + if (sz > 0) io_->read(buf + 1, sz - 1); + uint64_t size = returnTagValue(buf, sz); + + if (skip && !ignore) return; + + const uint64_t bufMinSize = 200; #ifndef SUPPRESS_WARNINGS - if (!ignore && size > bufMinSize) { - EXV_WARNING << "Size " << size << " of Matroska tag 0x" - << std::hex << mt->val_ << std::dec - << " is greater than " << bufMinSize << ": ignoring it.\n"; - } + if (!ignore && size > bufMinSize){ + EXV_WARNING << "Size " << size << " of Matroska tag 0x" + << std::hex << mt->val_ << std::dec + << " is greater than " << bufMinSize << ": ignoring it.\n"; + } #endif - if (ignore || size > bufMinSize) { - io_->seek(size, BasicIo::cur); - return; + if (ignore || size > bufMinSize){ + io_->seek(size, BasicIo::cur); + return; + } + + DataBuf buf2(bufMinSize+1); + int32_t s = static_cast(size) ; + io_->read(buf2.pData_,s); + contentManagement(mt, buf2.pData_,s); +} // MatroskaVideo::decodeBlock + +void MatroskaVideo::contentManagement(const MatroskaTags* mt, const Exiv2::byte* buf, int32_t size) +{ + int64_t duration_in_ms = 0; + static double time_code_scale = 1.0, temp = 0; + static int32_t stream = 0, track_count = 0; + char str[4] = "No"; + const RevMatroskaTags* rtd = 0; + const MatroskaTags* internalMt = 0; + const RevMatroskaTags* revTagStructure = 0; + + if(d->m_modifyMetadata){ + } + switch (mt->val_) { + + case 0x0282: case 0x0d80: case 0x1741: case 0x3ba9: case 0x066e: case 0x0660: + case 0x065c: case 0x067e: case 0x047a: case 0x0487: case 0x05a3: case 0x136e: + case 0x23ca: case 0xeb524: + if(!d->m_modifyMetadata) xmpData_[mt->label_] = buf; + else{ + if(xmpData_[mt->label_].count() > 0){ + Exiv2::byte* rawTagData = new byte[size]; + std::string tagData = xmpData_[mt->label_].toString(); + for(int32_t i=0; i (int32_t) tagData.size()) + for(int32_t i=(int32_t) tagData.size(); iseek(-size,BasicIo::cur); + io_->write(rawTagData,size); + delete[] rawTagData; + } } + break; - DataBuf buf2(bufMinSize+1); - std::memset(buf2.pData_, 0x0, buf2.size_); - long s = static_cast(size) ; - io_->read(buf2.pData_,s); - contentManagement(mt, buf2.pData_,s); - } // MatroskaVideo::decodeBlock - - void MatroskaVideo::contentManagement(const MatroskaTags* mt, const byte* buf, long size) - { - int64_t duration_in_ms = 0; - static double time_code_scale = 1.0, temp = 0; - static long stream = 0, track_count = 0; - char str[4] = "No"; - const MatroskaTags* internalMt = 0; - - switch (mt->val_) { - - case 0x0282: case 0x0d80: case 0x1741: case 0x3ba9: case 0x066e: case 0x0660: - case 0x065c: case 0x067e: case 0x047a: case 0x0487: case 0x05a3: case 0x136e: - case 0x23ca: case 0xeb524: - xmpData_[mt->label_] = buf; - break; - - case 0x0030: case 0x003a: case 0x0287: case 0x14b0: case 0x14ba: case 0x285: - case 0x06ae: case 0x0286: case 0x02f7: case 0x2264: case 0x14aa: case 0x14bb: - case 0x14cc: case 0x14dd: - xmpData_[mt->label_] = returnValue(buf, size); - - if (mt->val_ == 0x0030 || mt->val_ == 0x14b0) { - width_ = returnValue(buf, size); + case 0x0030: case 0x003a: case 0x0287: case 0x14b0: case 0x14ba: case 0x285: + case 0x06ae: case 0x0286: case 0x02f7: case 0x2264: case 0x14aa: case 0x14bb: + case 0x14cc: case 0x14dd: + if(!d->m_modifyMetadata) xmpData_[mt->label_] = returnValue(buf, size); + else{ + if(xmpData_[mt->label_].count() > 0){ + Exiv2::byte* rawTagData = returnBuf((uint64_t)xmpData_[mt->label_].toFloat(),size); + io_->seek(-size,BasicIo::cur); + io_->write(rawTagData,size); + free(rawTagData); } - else if (mt->val_ == 0x003a || mt->val_ == 0x14ba) { - height_ = returnValue(buf, size); - } - break; + } + if (mt->val_ == 0x0030 || mt->val_ == 0x14b0) d->width_ = returnValue(buf, size); + else if (mt->val_ == 0x003a || mt->val_ == 0x14ba) d->height_ = returnValue(buf, size); + break; - case 0x001a: case 0x001f: case 0x0254: case 0x07e1: case 0x07e5: case 0x07e6: - case 0x1033: case 0x14b2: case 0x14b3: case 0x23c3: case 0x29bf: case 0x3e8a: + case 0x001a: case 0x001f: case 0x0254: case 0x07e1: case 0x07e5: case 0x07e6: + case 0x1033: case 0x14b2: case 0x14b3: case 0x23c3: case 0x29bf: case 0x3e8a: + case 0x3e9a: + switch (mt->val_){ + case 0x001a: internalMt = find(videoScanType, returnValue(buf, size)); break; + case 0x001f: internalMt = find(audioChannels, returnValue(buf, size)); break; + case 0x0254: internalMt = find(compressionAlgorithm, returnValue(buf, size)); break; + case 0x07e1: internalMt = find(encryptionAlgorithm, returnValue(buf, size)); break; + case 0x1033: internalMt = find(encodingType, returnValue(buf, size)); break; + case 0x3e8a: + case 0x07e5: internalMt = find(contentSignatureAlgorithm, returnValue(buf, size)); break; case 0x3e9a: - switch (mt->val_) { - case 0x001a: internalMt = find(videoScanType, returnValue(buf, size)); break; - case 0x001f: internalMt = find(audioChannels, returnValue(buf, size)); break; - case 0x0254: internalMt = find(compressionAlgorithm, returnValue(buf, size)); break; - case 0x07e1: internalMt = find(encryptionAlgorithm, returnValue(buf, size)); break; - case 0x1033: internalMt = find(encodingType, returnValue(buf, size)); break; - case 0x3e8a: - case 0x07e5: internalMt = find(contentSignatureAlgorithm, returnValue(buf, size)); break; - case 0x3e9a: - case 0x07e6: internalMt = find(contentSignatureHashAlgorithm, returnValue(buf, size)); break; - case 0x14b2: internalMt = find(displayUnit, returnValue(buf, size)); break; - case 0x14b3: internalMt = find(aspectRatioType, returnValue(buf, size)); break; - case 0x23c3: internalMt = find(chapterPhysicalEquivalent, returnValue(buf, size)); break; - case 0x29bf: internalMt = find(chapterTranslateCodec, returnValue(buf, size)); break; + case 0x07e6: internalMt = find(contentSignatureHashAlgorithm, returnValue(buf, size)); break; + case 0x14b2: internalMt = find(displayUnit, returnValue(buf, size)); break; + case 0x14b3: internalMt = find(aspectRatioType, returnValue(buf, size)); break; + case 0x23c3: internalMt = find(chapterPhysicalEquivalent, returnValue(buf, size)); break; + case 0x29bf: internalMt = find(chapterTranslateCodec, returnValue(buf, size)); break; + } + if(!d->m_modifyMetadata) if (internalMt) xmpData_[mt->label_] = internalMt->label_; + else if(internalMt){ + if(xmpData_[mt->label_].count() >0){ + const int32_t videoTagSize = lengthof(videoScanType); + const int32_t audioTagSize = lengthof(audioChannels); + const int32_t compressionTagSize = lengthof(compressionAlgorithm); + const int32_t encryptionTagSize = lengthof(encryptionAlgorithm); + const int32_t encodingTagSize = lengthof(encodingType); + const int32_t contentTagSize = lengthof(contentSignatureAlgorithm); + const int32_t contentHashTagSize = lengthof(contentSignatureHashAlgorithm); + const int32_t displayTagSize = lengthof(displayUnit); + const int32_t aspectTagSize = lengthof(aspectRatioType); + const int32_t physicalTagSize = lengthof(chapterPhysicalEquivalent); + const int32_t translateTagSize = lengthof(chapterTranslateCodec); + + switch (mt->val_){ + case 0x001a: + RevMatroskaTags revVidStructure[videoTagSize]; + reverseMatroskaTag(videoScanType,revVidStructure,videoTagSize); + rtd = find(revVidStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x001f: + RevMatroskaTags revAudStructure[audioTagSize]; + reverseMatroskaTag(audioChannels,revAudStructure,audioTagSize); + rtd = find(revAudStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x0254: + RevMatroskaTags revComStructure[compressionTagSize]; + reverseMatroskaTag(compressionAlgorithm,revComStructure,compressionTagSize); + rtd = find(revComStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x07e1: + RevMatroskaTags revEnrStructure[encryptionTagSize]; + reverseMatroskaTag(encryptionAlgorithm,revEnrStructure,encryptionTagSize); + rtd = find(revEnrStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x1033: + RevMatroskaTags revEncStructure[encodingTagSize]; + reverseMatroskaTag(encodingType,revEncStructure,encodingTagSize); + rtd = find(revEncStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x07e5: + RevMatroskaTags revConStructure[contentTagSize]; + reverseMatroskaTag(contentSignatureAlgorithm,revConStructure,contentTagSize); + rtd = find(revConStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x07e6: + RevMatroskaTags revHasStructure[contentHashTagSize]; + reverseMatroskaTag(contentSignatureHashAlgorithm,revHasStructure,contentHashTagSize); + rtd = find(revHasStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x14b2: + RevMatroskaTags revDisStructure[displayTagSize]; + reverseMatroskaTag(displayUnit,revDisStructure,displayTagSize); + rtd = find(revDisStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x14b3: + RevMatroskaTags revAspStructure[aspectTagSize]; + reverseMatroskaTag(aspectRatioType,revAspStructure,aspectTagSize); + rtd = find(revAspStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x23c3: + RevMatroskaTags revPhyStructure[physicalTagSize]; + reverseMatroskaTag(chapterPhysicalEquivalent,revPhyStructure,physicalTagSize); + rtd = find(revPhyStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + case 0x29bf: + RevMatroskaTags revTraStructure[translateTagSize]; + reverseMatroskaTag(chapterTranslateCodec,revTraStructure,translateTagSize); + rtd = find(revTraStructure,xmpData_[mt->label_].toString()); + writeMatroskaKey(rtd,size);break; + } } - if (internalMt) xmpData_[mt->label_] = internalMt->label_; - break; - - case 0x0035: case 0x38b5: - xmpData_[mt->label_] = getFloat(buf, bigEndian); - break; - - case 0x0039: case 0x0008: case 0x15aa: case 0x001c: case 0x002a: case 0x1a9697: - case 0x0484: - if (returnValue(buf, size)) strcpy(str, "Yes"); - switch (mt->val_) { - case 0x0039: internalMt = find(trackEnable, stream); break; - case 0x0008: internalMt = find(defaultOn, stream); break; - case 0x15aa: internalMt = find(trackForced, stream); break; - case 0x001c: internalMt = find(trackLacing, stream); break; - case 0x002a: internalMt = find(codecDecodeAll, stream); break; - case 0x1a9697: internalMt = find(codecSettings, stream); break; - case 0x0484: internalMt = mt; break; + } + break; + case 0x0035: case 0x38b5: + if(!d->m_modifyMetadata) xmpData_[mt->label_] = getFloat(buf, bigEndian); + else if(xmpData_[mt->label_].count() > 0){ + Exiv2::byte *rawFloatValue = new byte[size]; + float floatValue = xmpData_[mt->label_].toFloat(); + memcpy(rawFloatValue,&floatValue,sizeof(float)); + // io_->seek(-size,BasicIo::cur);//Tobe tested + // io_->write(rawFloatValue,size); } - if (internalMt) xmpData_[internalMt->label_] = str; - break; + break; - case 0x0006: case 0x2b59c: case 0x58688: case 0x6b240: case 0x1b4040: - switch (mt->val_) { - case 0x0006: internalMt = find(trackCodec, stream); break; - case 0x2b59c: internalMt = find(trackLanguage, stream); break; - case 0x58688: internalMt = find(codecInfo, stream); break; - case 0x6b240: - case 0x1b4040: internalMt = find(codecDownloadUrl, stream); break; - } - if (internalMt) xmpData_[internalMt->label_] = buf; - break; + case 0x0039: case 0x0008: case 0x15aa: case 0x001c: case 0x002a: case 0x1a9697: + case 0x0484: + if (returnValue(buf, size)) strcpy(str, "Yes"); + switch (mt->val_){ + case 0x0039: internalMt = find(trackEnable, stream); break; + case 0x0008: internalMt = find(defaultOn, stream); break; + case 0x15aa: internalMt = find(trackForced, stream); break; + case 0x001c: internalMt = find(trackLacing, stream); break; + case 0x002a: internalMt = find(codecDecodeAll, stream); break; + case 0x1a9697: internalMt = find(codecSettings, stream); break; + case 0x0484: internalMt = mt; break; + } + if (internalMt) xmpData_[internalMt->label_] = str; + break; - case 0x0489: case 0x0461: - switch (mt->val_) { + case 0x0006: case 0x2b59c: case 0x58688: case 0x6b240: case 0x1b4040: + switch (mt->val_){ + case 0x0006: internalMt = find(trackCodec, stream); break; + case 0x2b59c: internalMt = find(trackLanguage, stream); break; + case 0x58688: internalMt = find(codecInfo, stream); break; + case 0x6b240: + case 0x1b4040: internalMt = find(codecDownloadUrl, stream); break; + } + if (internalMt) xmpData_[internalMt->label_] = buf; + break; + + case 0x0489: case 0x0461: + if(!d->m_modifyMetadata){ + switch (mt->val_){ case 0x0489: - if(size <= 4) { - duration_in_ms = static_cast(getFloat(buf, bigEndian) * time_code_scale * 1000); - } - else { - duration_in_ms = static_cast(getDouble(buf, bigEndian) * time_code_scale * 1000); - } + if(size <= 4) duration_in_ms = static_cast(getFloat(buf, bigEndian) * time_code_scale * 1000); + else duration_in_ms = static_cast(getDouble(buf, bigEndian) * time_code_scale * 1000); break; - case 0x0461: { - duration_in_ms = returnValue(buf, size)/1000000000; break; - } + case 0x0461: duration_in_ms = returnValue(buf, size)/1000000000; break; } xmpData_[mt->label_] = duration_in_ms; - break; + } + else{ + Exiv2::byte *rawDuration; + switch (mt->val_){ + case 0x0489: + rawDuration = returnBuf( (uint64_t) (xmpData_[mt->label_].toFloat() /(time_code_scale*1000.0)),size); + io_->seek(-size,BasicIo::cur); + io_->write(rawDuration,size); + break; + case 0x0461: + rawDuration = returnBuf( (uint64_t) (xmpData_[mt->label_].toFloat() / 1000000000.0),size); + io_->seek(-size,BasicIo::cur); + io_->write(rawDuration,size); + break; + } + free(rawDuration); + } + break; - case 0x0057: - track_count++; - xmpData_["Xmp.video.TotalStream"] = track_count; - break; + case 0x0057: + track_count++; + xmpData_["Xmp.video.TotalStream"] = track_count; + break; - case 0xad7b1: + case 0xad7b1: + if(!d->m_modifyMetadata){ time_code_scale = (double)returnValue(buf, size)/(double)1000000000; xmpData_["Xmp.video.TimecodeScale"] = time_code_scale; - break; + } + else{ + Exiv2::byte *rawTimeCodeScale = returnBuf((uint64_t)(xmpData_["Xmp.video.TimecodeScale"] + .toFloat()*1000000000),size); + io_->seek(size,BasicIo::cur); + io_->write(rawTimeCodeScale,size); + free(rawTimeCodeScale); + } + break; - case 0x0003: - internalMt = find(matroskaTrackType, returnValue(buf, size)); - stream = static_cast(internalMt->val_); - break; + case 0x0003: + internalMt = find(matroskaTrackType, returnValue(buf, size)); + stream = static_cast(internalMt->val_); + break; - case 0x3e383: case 0x383e3: - internalMt = find(streamRate, stream); - if (returnValue(buf, size)) { - switch (stream) { - case 1: temp = (double)1000000000/(double)returnValue(buf, size); break; - case 2: temp = static_cast(returnValue(buf, size) / 1000); break; - } - if (internalMt) xmpData_[internalMt->label_] = temp; + case 0x3e383: case 0x383e3: + internalMt = find(streamRate, stream); + if (returnValue(buf, size)){ + switch (stream) + { + case 1: temp = (double)1000000000/(double)returnValue(buf, size); break; + case 2: temp = static_cast(returnValue(buf, size) / 1000); break; } - else - if (internalMt) xmpData_[internalMt->label_] = "Variable Bit Rate"; - break; - - default: - break; + if (internalMt) xmpData_[internalMt->label_] = temp; } - } // MatroskaVideo::contentManagement + else if (internalMt) xmpData_[internalMt->label_] = "Variable Bit Rate"; break; - void MatroskaVideo::aspectRatio() - { - //TODO - Make a better unified method to handle all cases of Aspect Ratio - - double aspectRatio = (double)width_ / (double)height_; - aspectRatio = floor(aspectRatio*10) / 10; - xmpData_["Xmp.video.AspectRatio"] = aspectRatio; - - int aR = (int) ((aspectRatio*10.0)+0.1); - - switch (aR) { - case 13 : xmpData_["Xmp.video.AspectRatio"] = "4:3" ; break; - case 17 : xmpData_["Xmp.video.AspectRatio"] = "16:9" ; break; - case 10 : xmpData_["Xmp.video.AspectRatio"] = "1:1" ; break; - case 16 : xmpData_["Xmp.video.AspectRatio"] = "16:10" ; break; - case 22 : xmpData_["Xmp.video.AspectRatio"] = "2.21:1" ; break; - case 23 : xmpData_["Xmp.video.AspectRatio"] = "2.35:1" ; break; - case 12 : xmpData_["Xmp.video.AspectRatio"] = "5:4" ; break; - default : xmpData_["Xmp.video.AspectRatio"] = aspectRatio;break; - } - } // MatroskaVideo::aspectRatio - - uint32_t MatroskaVideo::findBlockSize(byte b) - { - if (b & 128) return 1; - else if (b & 64) return 2; - else if (b & 32) return 3; - else if (b & 16) return 4; - else if (b & 8) return 5; - else if (b & 4) return 6; - else if (b & 2) return 7; - else if (b & 1) return 8; - else return 0; - } // MatroskaVideo::findBlockSize - - Image::AutoPtr newMkvInstance(BasicIo::AutoPtr io, bool /*create*/) - { - Image::AutoPtr image(new MatroskaVideo(io)); - if (!image->good()) { - image.reset(); - } - return image; + default: break; } +} // MatroskaVideo::contentManagement - bool isMkvType(BasicIo& iIo, bool advance) - { - bool result = true; - byte tmpBuf[4]; - iIo.read(tmpBuf, 4); +void MatroskaVideo::aspectRatio() +{ + //TODO - Make a better unified method to handle all cases of Aspect Ratio - if (iIo.error() || iIo.eof()) return false; + double aspectRatio = (double)d->width_ / (double)d->height_; + aspectRatio = floor(aspectRatio*10) / 10; + xmpData_["Xmp.video.AspectRatio"] = aspectRatio; - if (0x1a != tmpBuf[0] || 0x45 != tmpBuf[1] || 0xdf != tmpBuf[2] || 0xa3 != tmpBuf[3]) { - result = false; - } + int aR = (int) ((aspectRatio*10.0)+0.1); - if (!advance || !result ) iIo.seek(0, BasicIo::beg); - return result; + switch (aR) { + case 13 : xmpData_["Xmp.video.AspectRatio"] = "4:3" ; break; + case 17 : xmpData_["Xmp.video.AspectRatio"] = "16:9" ; break; + case 10 : xmpData_["Xmp.video.AspectRatio"] = "1:1" ; break; + case 16 : xmpData_["Xmp.video.AspectRatio"] = "16:10" ; break; + case 22 : xmpData_["Xmp.video.AspectRatio"] = "2.21:1" ; break; + case 23 : xmpData_["Xmp.video.AspectRatio"] = "2.35:1" ; break; + case 12 : xmpData_["Xmp.video.AspectRatio"] = "5:4" ; break; + default : xmpData_["Xmp.video.AspectRatio"] = aspectRatio;break; } +} // MatroskaVideo::aspectRatio + +uint32_t MatroskaVideo::findBlockSize(Exiv2::byte b) +{ + if (b & 128) return 1; + else if (b & 64) return 2; + else if (b & 32) return 3; + else if (b & 16) return 4; + else if (b & 8) return 5; + else if (b & 4) return 6; + else if (b & 2) return 7; + else if (b & 1) return 8; + else return 0; +} // MatroskaVideo::findBlockSize + +Image::AutoPtr newMkvInstance(BasicIo::AutoPtr io, bool /*create*/) +{ + Image::AutoPtr image(new MatroskaVideo(io)); + if (!image->good()) image.reset(); + return image; +} + +void MatroskaVideo::writeStringData(Exiv2::Xmpdatum xmpStringData, int32_t size, int32_t skipOffset) +{ + if(xmpStringData.count() > 0){ + std::string dataString = xmpStringData.toString(); + Exiv2::byte* rawData = new byte[(uint8_t)size]; + int32_t newSize = (int32_t)dataString.size(); + for(int32_t i=0; i newSize) + for(int32_t i=newSize; iwrite(rawData,size); + io_->seek((int)skipOffset,BasicIo::cur); + delete[] rawData; + } + else io_->seek((size+skipOffset),BasicIo::cur); +} + +void MatroskaVideo::writeMatroskaKey(const RevMatroskaTags* revInternalMt,int32_t size) +{ + if(revInternalMt){ + Exiv2::byte* rawMatroskaKey = returnBuf(revInternalMt->val_,size); + io_->seek(-size,BasicIo::cur); + io_->write(rawMatroskaKey,size); + free(rawMatroskaKey); + } +} + +bool isMkvType(BasicIo& iIo, bool advance) +{ + bool result = true; + Exiv2::byte tmpBuf[4]; + iIo.read(tmpBuf, 4); + + if (iIo.error() || iIo.eof()) return false; + + if (0x1a != tmpBuf[0] || 0x45 != tmpBuf[1] || 0xdf != tmpBuf[2] || 0xa3 != tmpBuf[3]) result = false; + + if (!advance || !result ) iIo.seek(0, BasicIo::beg); + return result; +} } // namespace Exiv2 diff --git a/src/matroskavideo.hpp b/src/matroskavideo.hpp index a86fb0c5..43827f61 100644 --- a/src/matroskavideo.hpp +++ b/src/matroskavideo.hpp @@ -37,36 +37,51 @@ // ***************************************************************************** // namespace extensions -namespace Exiv2 { +namespace Exiv2 +{ // ***************************************************************************** // class definitions - // Add MKV to the supported image formats - namespace ImageType { - const int mkv = 21; //!< Treating mkv as an image type> - } +// Add MKV to the supported image formats +namespace ImageType +{ +const int mkv = 21; //!< Treating mkv as an image type> +} - // Todo: Should be hidden - /*! +// Todo: Should be hidden +/*! @brief Helper structure for the Matroska tags lookup table. */ - struct MatroskaTags { - uint64_t val_; //!< Tag value - const char* label_; //!< Translation of the tag value +struct MatroskaTags +{ + uint64_t val_; //!< Tag value + const char* label_; //!< Translation of the tag value - //! Comparison operator for use with the find template - bool operator==(uint64_t key) const { return val_ == key; } - }; // struct TagDetails + //! Comparison operator for use with the find template + bool operator==(uint64_t key) const { return val_ == key; } +}; // struct TagDetails - /*! +/*! + * \brief The RevMatroskaTags struct reverse the matroskatag structure. + */ +struct RevMatroskaTags +{ + const char* label_; //!< Translation of the tag value + uint64_t val_; //!< Tag value + + //! Comparison operator for use with the find template + bool operator==(const std::string& key) const{return label_ == key;} +}; +/*! @brief Class to access Matroska video files. */ - class EXIV2API MatroskaVideo : public Image { - public: - //! @name Creators - //@{ - /*! +class EXIV2API MatroskaVideo : public Image +{ +public: + //! @name Creators + //@{ + /*! @brief Constructor for a Matroska video. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @@ -77,22 +92,22 @@ namespace Exiv2 { instance after it is passed to this method. Use the Image::io() method to get a temporary reference. */ - MatroskaVideo(BasicIo::AutoPtr io); - //@} + MatroskaVideo(BasicIo::AutoPtr io); + //@} - //! @name Manipulators - //@{ - void readMetadata(); - void writeMetadata(); - //@} + //! @name Manipulators + //@{ + void readMetadata(); + void writeMetadata(); + //@} - //! @name Accessors - //@{ - std::string mimeType() const; - //@} + //! @name Accessors + //@{ + std::string mimeType() const; + //@} - protected: - /*! +protected: + /*! @brief Function used to calulate the size of a block. This information is only stored in one byte. The size of the block is calculated by counting @@ -101,56 +116,79 @@ namespace Exiv2 { @param b The byte, which stores the information to calculate the size @return Return the size of the block. */ - uint32_t findBlockSize(byte b); - /*! + uint32_t findBlockSize(byte b); + /*! @brief Check for a valid tag and decode the block at the current IO position. Calls contentManagement() or skips to next tag, if required. */ - void decodeBlock(); - /*! + void decodeBlock(); + /*! @brief Interpret tag information, and save it in the respective XMP container. @param mt Pointer to current tag, @param buf Pointer to the memory area with the tag information. @param size Size of \em buf. */ - void contentManagement(const MatroskaTags* mt, const byte* buf, long size); - /*! + void contentManagement(const MatroskaTags* mt, const Exiv2::byte* buf, int32_t size); + /*! @brief Calculates Aspect Ratio of a video, and stores it in the respective XMP container. */ - void aspectRatio(); + void aspectRatio(); - private: - //! @name NOT Implemented - //@{ - //! Copy constructor - MatroskaVideo(const MatroskaVideo& rhs); - //! Assignment operator - MatroskaVideo& operator=(const MatroskaVideo& rhs); - //@} +private: + //! @name NOT Implemented + //@{ + //! Copy constructor + MatroskaVideo(const MatroskaVideo& rhs); + //! Assignment operator + MatroskaVideo& operator=(const MatroskaVideo& rhs); + ~MatroskaVideo(); + //@} + /*! + @brief Provides the main implementation of writeMetadata() by + writing all buffered metadata to the provided BasicIo. + @param oIo BasicIo instance to write to (a temporary location). - private: - //! Variable to check the end of metadata traversing. - bool continueTraversing_; - //! Variable to store height and width of a video frame. - uint64_t height_, width_; + @return 4 if opening or writing to the associated BasicIo fails + */ + EXV_DLLLOCAL void doWriteMetadata(); - }; // class MatroskaVideo + /*! + * \brief writeStringData + * \param xmpStringData + * \param size + * \param skipOffset + */ + void writeStringData(Exiv2::Xmpdatum xmpStringData, int32_t size, int32_t skipOffset=0); + + /*! + * \brief writeMatroskaKey + * \param inputStruct + * \param size + */ + void writeMatroskaKey(const RevMatroskaTags *revInternalMt, int32_t size); + +private: + + class Private; + Private * const d; + +}; // class MatroskaVideo // ***************************************************************************** // template, inline and free functions - // These could be static private functions on Image subclasses but then - // ImageFactory needs to be made a friend. - /*! +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! @brief Create a new MatroskaVideo instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ - EXIV2API Image::AutoPtr newMkvInstance(BasicIo::AutoPtr io, bool create); +EXIV2API Image::AutoPtr newMkvInstance(BasicIo::AutoPtr io, bool create); - //! Check if the file iIo is a Matroska Video. - EXIV2API bool isMkvType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a Matroska Video. +EXIV2API bool isMkvType(BasicIo& iIo, bool advance); } // namespace Exiv2 diff --git a/src/quicktimevideo.cpp b/src/quicktimevideo.cpp index 7878314c..9fc17849 100644 --- a/src/quicktimevideo.cpp +++ b/src/quicktimevideo.cpp @@ -11,7 +11,7 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License @@ -19,11 +19,12 @@ * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /* - File: quicktimevideo.cpp - Version: $Rev$ + File: quicktimevideo.cpp + Version: $Rev$ Author(s): Abhinav Badola for GSoC 2012 (AB) - History: 28-Jun-12, AB: created - Credits: See header file + Mahesh Hegde for GSoC 2013 + History: 28-Jun-12, AB: created + Credits: See header file */ // ***************************************************************************** #include "rcsid_int.hpp" @@ -35,924 +36,1599 @@ EXIV2_RCSID("@(#) $Id$") #include "futils.hpp" #include "basicio.hpp" #include "tags.hpp" +#include "utilsvideo.hpp" + // + standard includes #include +#include + +#ifndef _MSC_VER +#define stricmp strcasecmp +#endif + +typedef void (Exiv2::QuickTimeVideo::*decFunc)(uint32_t); // ***************************************************************************** // class member definitions -namespace Exiv2 { - namespace Internal { +namespace Exiv2{ +namespace Internal{ - extern const TagVocabulary qTimeFileType[] = { - { "3g2a", "3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-0 V1.0" }, - { "3g2b", "3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-A V1.0.0" }, - { "3g2c", "3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-B v1.0" }, - { "3ge6", "3GPP (.3GP) Release 6 MBMS Extended Presentations" }, - { "3ge7", "3GPP (.3GP) Release 7 MBMS Extended Presentations" }, - { "3gg6", "3GPP Release 6 General Profile" }, - { "3gp1", "3GPP Media (.3GP) Release 1 (probably non-existent)" }, - { "3gp2", "3GPP Media (.3GP) Release 2 (probably non-existent)" }, - { "3gp3", "3GPP Media (.3GP) Release 3 (probably non-existent)" }, - { "3gp4", "3GPP Media (.3GP) Release 4" }, - { "3gp5", "3GPP Media (.3GP) Release 5" }, - { "3gp6", "3GPP Media (.3GP) Release 6 Streaming Servers" }, - { "3gs7", "3GPP Media (.3GP) Release 7 Streaming Servers" }, - { "CAEP", "Canon Digital Camera" }, - { "CDes", "Convergent Design" }, - { "F4A ", "Audio for Adobe Flash Player 9+ (.F4A)" }, - { "F4B ", "Audio Book for Adobe Flash Player 9+ (.F4B)" }, - { "F4P ", "Protected Video for Adobe Flash Player 9+ (.F4P)" }, - { "F4V ", "Video for Adobe Flash Player 9+ (.F4V)" }, - { "JP2 ", "JPEG 2000 Image (.JP2) [ISO 15444-1 ?]" }, - { "JP20", "Unknown, from GPAC samples (prob non-existent)" }, - { "KDDI", "3GPP2 EZmovie for KDDI 3G cellphones" }, - { "M4A ", "Apple iTunes AAC-LC (.M4A) Audio" }, - { "M4B ", "Apple iTunes AAC-LC (.M4B) Audio Book" }, - { "M4P ", "Apple iTunes AAC-LC (.M4P) AES Protected Audio" }, - { "M4V ", "Apple iTunes Video (.M4V) Video" }, - { "M4VH", "Apple TV (.M4V)" }, - { "M4VP", "Apple iPhone (.M4V)" }, - { "MPPI", "Photo Player, MAF [ISO/IEC 23000-3]" }, - { "MSNV", "MPEG-4 (.MP4) for SonyPSP" }, - { "NDAS", "MP4 v2 [ISO 14496-14] Nero Digital AAC Audio" }, - { "NDSC", "MPEG-4 (.MP4) Nero Cinema Profile" }, - { "NDSH", "MPEG-4 (.MP4) Nero HDTV Profile" }, - { "NDSM", "MPEG-4 (.MP4) Nero Mobile Profile" }, - { "NDSP", "MPEG-4 (.MP4) Nero Portable Profile" }, - { "NDSS", "MPEG-4 (.MP4) Nero Standard Profile" }, - { "NDXC", "H.264/MPEG-4 AVC (.MP4) Nero Cinema Profile" }, - { "NDXH", "H.264/MPEG-4 AVC (.MP4) Nero HDTV Profile" }, - { "NDXM", "H.264/MPEG-4 AVC (.MP4) Nero Mobile Profile" }, - { "NDXP", "H.264/MPEG-4 AVC (.MP4) Nero Portable Profile" }, - { "NDXS", "H.264/MPEG-4 AVC (.MP4) Nero Standard Profile" }, - { "NIKO", "Nikon" }, - { "ROSS", "Ross Video" }, - { "avc1", "MP4 Base w/ AVC ext [ISO 14496-12:2005]" }, - { "caqv", "Casio Digital Camera" }, - { "da0a", "DMB MAF w/ MPEG Layer II aud, MOT slides, DLS, JPG/PNG/MNG images" }, - { "da0b", "DMB MAF, extending DA0A, with 3GPP timed text, DID, TVA, REL, IPMP" }, - { "da1a", "DMB MAF audio with ER-BSAC audio, JPG/PNG/MNG images" }, - { "da1b", "DMB MAF, extending da1a, with 3GPP timed text, DID, TVA, REL, IPMP" }, - { "da2a", "DMB MAF aud w/ HE-AAC v2 aud, MOT slides, DLS, JPG/PNG/MNG images" }, - { "da2b", "DMB MAF, extending da2a, with 3GPP timed text, DID, TVA, REL, IPMP" }, - { "da3a", "DMB MAF aud with HE-AAC aud, JPG/PNG/MNG images" }, - { "da3b", "DMB MAF, extending da3a w/ BIFS, 3GPP timed text, DID, TVA, REL, IPMP" }, - { "dmb1", "DMB MAF supporting all the components defined in the specification" }, - { "dmpf", "Digital Media Project" }, - { "drc1", "Dirac (wavelet compression), encapsulated in ISO base media (MP4)" }, - { "dv1a", "DMB MAF vid w/ AVC vid, ER-BSAC aud, BIFS, JPG/PNG/MNG images, TS" }, - { "dv1b", "DMB MAF, extending dv1a, with 3GPP timed text, DID, TVA, REL, IPMP" }, - { "dv2a", "DMB MAF vid w/ AVC vid, HE-AAC v2 aud, BIFS, JPG/PNG/MNG images, TS" }, - { "dv2b", "DMB MAF, extending dv2a, with 3GPP timed text, DID, TVA, REL, IPMP" }, - { "dv3a", "DMB MAF vid w/ AVC vid, HE-AAC aud, BIFS, JPG/PNG/MNG images, TS" }, - { "dv3b", "DMB MAF, extending dv3a, with 3GPP timed text, DID, TVA, REL, IPMP" }, - { "dvr1", "DVB (.DVB) over RTP" }, - { "dvt1", "DVB (.DVB) over MPEG-2 Transport Stream" }, - { "isc2", "ISMACryp 2.0 Encrypted File" }, - { "iso2", "MP4 Base Media v2 [ISO 14496-12:2005]" }, - { "isom", "MP4 Base Media v1 [IS0 14496-12:2003]" }, - { "jpm ", "JPEG 2000 Compound Image (.JPM) [ISO 15444-6]" }, - { "jpx ", "JPEG 2000 with extensions (.JPX) [ISO 15444-2]" }, - { "mj2s", "Motion JPEG 2000 [ISO 15444-3] Simple Profile" }, - { "mjp2", "Motion JPEG 2000 [ISO 15444-3] General Profile" }, - { "mmp4", "MPEG-4/3GPP Mobile Profile (.MP4/3GP) (for NTT)" }, - { "mp21", "MPEG-21 [ISO/IEC 21000-9]" }, - { "mp41", "MP4 v1 [ISO 14496-1:ch13]" }, - { "mp42", "MP4 v2 [ISO 14496-14]" }, - { "mp71", "MP4 w/ MPEG-7 Metadata [per ISO 14496-12]" }, - { "mqt ", "Sony / Mobile QuickTime (.MQV) US Patent 7,477,830 (Sony Corp)" }, - { "niko", "Nikon" }, - { "odcf", "OMA DCF DRM Format 2.0 (OMA-TS-DRM-DCF-V2_0-20060303-A)" }, - { "opf2", "OMA PDCF DRM Format 2.1 (OMA-TS-DRM-DCF-V2_1-20070724-C)" }, - { "opx2", "OMA PDCF DRM + XBS extensions (OMA-TS-DRM_XBS-V1_0-20070529-C)" }, - { "pana", "Panasonic Digital Camera" }, - { "qt ", "Apple QuickTime (.MOV/QT)" }, - { "sdv ", "SD Memory Card Video" }, - { "ssc1", "Samsung stereoscopic, single stream" }, - { "ssc2", "Samsung stereoscopic, dual stream" } +//! File type information. +extern const TagVocabulary qTimeFileType[] = { + { "3g2a", "3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-0 V1.0" }, + { "3g2b", "3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-A V1.0.0" }, + { "3g2c", "3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-B v1.0" }, + { "3ge6", "3GPP (.3GP) Release 6 MBMS Extended Presentations" }, + { "3ge7", "3GPP (.3GP) Release 7 MBMS Extended Presentations" }, + { "3gg6", "3GPP Release 6 General Profile" }, + { "3gp1", "3GPP Media (.3GP) Release 1 (probably non-existent)" }, + { "3gp2", "3GPP Media (.3GP) Release 2 (probably non-existent)" }, + { "3gp3", "3GPP Media (.3GP) Release 3 (probably non-existent)" }, + { "3gp4", "3GPP Media (.3GP) Release 4" }, + { "3gp5", "3GPP Media (.3GP) Release 5" }, + { "3gp6", "3GPP Media (.3GP) Release 6 Streaming Servers" }, + { "3gs7", "3GPP Media (.3GP) Release 7 Streaming Servers" }, + { "CAEP", "Canon Digital Camera" }, + { "CDes", "Convergent Design" }, + { "F4A ", "Audio for Adobe Flash Player 9+ (.F4A)" }, + { "F4B ", "Audio Book for Adobe Flash Player 9+ (.F4B)" }, + { "F4P ", "Protected Video for Adobe Flash Player 9+ (.F4P)" }, + { "F4V ", "Video for Adobe Flash Player 9+ (.F4V)" }, + { "JP2 ", "JPEG 2000 Image (.JP2) [ISO 15444-1 ?]" }, + { "JP20", "Unknown, from GPAC samples (prob non-existent)" }, + { "KDDI", "3GPP2 EZmovie for KDDI 3G cellphones" }, + { "M4A ", "Apple iTunes AAC-LC (.M4A) Audio" }, + { "M4B ", "Apple iTunes AAC-LC (.M4B) Audio Book" }, + { "M4P ", "Apple iTunes AAC-LC (.M4P) AES Protected Audio" }, + { "M4V ", "Apple iTunes Video (.M4V) Video" }, + { "M4VH", "Apple TV (.M4V)" }, + { "M4VP", "Apple iPhone (.M4V)" }, + { "MPPI", "Photo Player, MAF [ISO/IEC 23000-3]" }, + { "MSNV", "MPEG-4 (.MP4) for SonyPSP" }, + { "NDAS", "MP4 v2 [ISO 14496-14] Nero Digital AAC Audio" }, + { "NDSC", "MPEG-4 (.MP4) Nero Cinema Profile" }, + { "NDSH", "MPEG-4 (.MP4) Nero HDTV Profile" }, + { "NDSM", "MPEG-4 (.MP4) Nero Mobile Profile" }, + { "NDSP", "MPEG-4 (.MP4) Nero Portable Profile" }, + { "NDSS", "MPEG-4 (.MP4) Nero Standard Profile" }, + { "NDXC", "H.264/MPEG-4 AVC (.MP4) Nero Cinema Profile" }, + { "NDXH", "H.264/MPEG-4 AVC (.MP4) Nero HDTV Profile" }, + { "NDXM", "H.264/MPEG-4 AVC (.MP4) Nero Mobile Profile" }, + { "NDXP", "H.264/MPEG-4 AVC (.MP4) Nero Portable Profile" }, + { "NDXS", "H.264/MPEG-4 AVC (.MP4) Nero Standard Profile" }, + { "NIKO", "Nikon" }, + { "ROSS", "Ross Video" }, + { "avc1", "MP4 Base w/ AVC ext [ISO 14496-12:2005]" }, + { "caqv", "Casio Digital Camera" }, + { "da0a", "DMB MAF w/ MPEG Layer II aud, MOT slides, DLS, JPG/PNG/MNG images" }, + { "da0b", "DMB MAF, extending DA0A, with 3GPP timed text, DID, TVA, REL, IPMP" }, + { "da1a", "DMB MAF audio with ER-BSAC audio, JPG/PNG/MNG images" }, + { "da1b", "DMB MAF, extending da1a, with 3GPP timed text, DID, TVA, REL, IPMP" }, + { "da2a", "DMB MAF aud w/ HE-AAC v2 aud, MOT slides, DLS, JPG/PNG/MNG images" }, + { "da2b", "DMB MAF, extending da2a, with 3GPP timed text, DID, TVA, REL, IPMP" }, + { "da3a", "DMB MAF aud with HE-AAC aud, JPG/PNG/MNG images" }, + { "da3b", "DMB MAF, extending da3a w/ BIFS, 3GPP timed text, DID, TVA, REL, IPMP" }, + { "dmb1", "DMB MAF supporting all the components defined in the specification" }, + { "dmpf", "Digital Media Project" }, + { "drc1", "Dirac (wavelet compression), encapsulated in ISO base media (MP4)" }, + { "dv1a", "DMB MAF vid w/ AVC vid, ER-BSAC aud, BIFS, JPG/PNG/MNG images, TS" }, + { "dv1b", "DMB MAF, extending dv1a, with 3GPP timed text, DID, TVA, REL, IPMP" }, + { "dv2a", "DMB MAF vid w/ AVC vid, HE-AAC v2 aud, BIFS, JPG/PNG/MNG images, TS" }, + { "dv2b", "DMB MAF, extending dv2a, with 3GPP timed text, DID, TVA, REL, IPMP" }, + { "dv3a", "DMB MAF vid w/ AVC vid, HE-AAC aud, BIFS, JPG/PNG/MNG images, TS" }, + { "dv3b", "DMB MAF, extending dv3a, with 3GPP timed text, DID, TVA, REL, IPMP" }, + { "dvr1", "DVB (.DVB) over RTP" }, + { "dvt1", "DVB (.DVB) over MPEG-2 Transport Stream" }, + { "isc2", "ISMACryp 2.0 Encrypted File" }, + { "iso2", "MP4 Base Media v2 [ISO 14496-12:2005]" }, + { "isom", "MP4 Base Media v1 [IS0 14496-12:2003]" }, + { "jpm ", "JPEG 2000 Compound Image (.JPM) [ISO 15444-6]" }, + { "jpx ", "JPEG 2000 with extensions (.JPX) [ISO 15444-2]" }, + { "mj2s", "Motion JPEG 2000 [ISO 15444-3] Simple Profile" }, + { "mjp2", "Motion JPEG 2000 [ISO 15444-3] General Profile" }, + { "mmp4", "MPEG-4/3GPP Mobile Profile (.MP4/3GP) (for NTT)" }, + { "mp21", "MPEG-21 [ISO/IEC 21000-9]" }, + { "mp41", "MP4 v1 [ISO 14496-1:ch13]" }, + { "mp42", "MP4 v2 [ISO 14496-14]" }, + { "mp71", "MP4 w/ MPEG-7 Metadata [per ISO 14496-12]" }, + { "mqt ", "Sony / Mobile QuickTime (.MQV) US Patent 7,477,830 (Sony Corp)" }, + { "niko", "Nikon" }, + { "odcf", "OMA DCF DRM Format 2.0 (OMA-TS-DRM-DCF-V2_0-20060303-A)" }, + { "opf2", "OMA PDCF DRM Format 2.1 (OMA-TS-DRM-DCF-V2_1-20070724-C)" }, + { "opx2", "OMA PDCF DRM + XBS extensions (OMA-TS-DRM_XBS-V1_0-20070529-C)" }, + { "pana", "Panasonic Digital Camera" }, + { "qt ", "Apple QuickTime (.MOV/QT)" }, + { "sdv ", "SD Memory Card Video" }, + { "ssc1", "Samsung stereoscopic, single stream" }, + { "ssc2", "Samsung stereoscopic, dual stream" }, +}; + +//! hadler Class Information. +extern const TagVocabulary handlerClassTags[] ={ + { "dhlr", "Data Handler" }, + { "mhlr", "Media Handler" } +}; + +//! Handler Type Information. +extern const TagVocabulary handlerTypeTags[] ={ + { "alis", "Alias Data" }, + { "crsm", "Clock Reference" }, + { "hint", "Hint Track" }, + { "ipsm", "IPMP" }, + { "m7sm", "MPEG-7 Stream" }, + { "mdir", "Metadata" }, + { "mdta", "Metadata Tags" }, + { "mjsm", "MPEG-J" }, + { "ocsm", "Object Content" }, + { "odsm", "Object Descriptor" }, + { "sdsm", "Scene Description" }, + { "soun", "Audio Track" }, + { "text", "Text" }, + { "tmcd", "Time Code" }, + { "url ", "URL" }, + { "vide", "Video Track" } +}; + +//! Vendor Id information. +extern const TagVocabulary vendorIDTags[] ={ + { "FFMP", "FFmpeg" }, + { "appl", "Apple" }, + { "olym", "Olympus" }, + { "GIC ", "General Imaging Co." }, + { "fe20", "Olympus (fe20)" }, + { "pana", "Panasonic" }, + { "KMPI", "Konica-Minolta" }, + { "kdak", "Kodak" }, + { "pent", "Pentax" }, + { "NIKO", "Nikon" }, + { "leic", "Leica" }, + { "pr01", "Olympus (pr01)" }, + { "SMI ", "Sorenson Media Inc." }, + { "mino", "Minolta" }, + { "sany", "Sanyo" }, + { "ZORA", "Zoran Corporation" }, + { "niko", "Nikon" } +}; + +//! Camera Information. +extern const TagVocabulary cameraByteOrderTags[] ={ + { "II", "Little-endian (Intel, II)" }, + { "MM", "Big-endian (Motorola, MM)" } +}; + +//! Graphics related Information. +extern const TagDetails graphicsModetags[] ={ + { 0x0, "srcCopy" }, + { 0x1, "srcOr" }, + { 0x2, "srcXor" }, + { 0x3, "srcBic" }, + { 0x4, "notSrcCopy" }, + { 0x5, "notSrcOr" }, + { 0x6, "notSrcXor" }, + { 0x7, "notSrcBic" }, + { 0x8, "patCopy" }, + { 0x9, "patOr" }, + { 0xa, "patXor" }, + { 0xb, "patBic" }, + { 0xc, "notPatCopy" }, + { 0xd, "notPatOr" }, + { 0xe, "notPatXor" }, + { 0xf, "notPatBic" }, + { 0x20, "blend" }, + { 0x21, "addPin" }, + { 0x22, "addOver" }, + { 0x23, "subPin" }, + { 0x24, "transparent" }, + { 0x25, "addMax" }, + { 0x26, "subOver" }, + { 0x27, "addMin" }, + { 0x31, "grayishTextOr" }, + { 0x32, "hilite" }, + { 0x40, "ditherCopy" }, + { 0x100, "Alpha" }, + { 0x101, "White Alpha" }, + { 0x102, "Pre-multiplied Black Alpha" }, + { 0x110, "Component Alpha" } +}; + +//! Media Language Codes. +extern const TagDetails mediaLanguageCode[] ={ + { 0x0, "English" }, + { 0x1, "French" }, + { 0x2, "German" }, + { 0x3, "Italian" }, + { 0x4, "Dutch" }, + { 0x5, "Swedish" }, + { 0x6, "Spanish" }, + { 0x7, "Danish" }, + { 0x8, "Portuguese" }, + { 0x9, "Norwegian" }, + { 0xa, "Hebrew" }, + { 0xb, "Japanese" }, + { 0xc, "Arabic" }, + { 0xd, "Finnish" }, + { 0xe, "Greek" }, + { 0xf, "Icelandic" }, + { 0x10, "Maltese" }, + { 0x11, "Turkish" }, + { 0x12, "Croatian" }, + { 0x13, "Traditional Chinese" }, + { 0x14, "Urdu" }, + { 0x15, "Hindi" }, + { 0x16, "Thai" }, + { 0x17, "Korean" }, + { 0x18, "Lithuanian" }, + { 0x19, "Polish" }, + { 0x1a, "Hungarian" }, + { 0x1b, "Estonian" }, + { 0x1c, "Lettish" }, + { 0x1c, "Latvian" }, + { 0x1d, "Saami" }, + { 0x1d, "Sami" }, + { 0x1e, "Faroese" }, + { 0x1f, "Farsi" }, + { 0x20, "Russian" }, + { 0x21, "Simplified Chinese" }, + { 0x22, "Flemish" }, + { 0x23, "Irish" }, + { 0x24, "Albanian" }, + { 0x25, "Romanian" }, + { 0x26, "Czech" }, + { 0x27, "Slovak" }, + { 0x28, "Slovenian" }, + { 0x29, "Yiddish" }, + { 0x2a, "Serbian" }, + { 0x2b, "Macedonian" }, + { 0x2c, "Bulgarian" }, + { 0x2d, "Ukrainian" }, + { 0x2e, "Belarusian" }, + { 0x2f, "Uzbek" }, + { 0x30, "Kazakh" }, + { 0x31, "Azerbaijani" }, + { 0x32, "AzerbaijanAr" }, + { 0x33, "Armenian" }, + { 0x34, "Georgian" }, + { 0x35, "Moldavian" }, + { 0x36, "Kirghiz" }, + { 0x37, "Tajiki" }, + { 0x38, "Turkmen" }, + { 0x39, "Mongolian" }, + { 0x3a, "MongolianCyr" }, + { 0x3b, "Pashto" }, + { 0x3c, "Kurdish" }, + { 0x3d, "Kashmiri" }, + { 0x3e, "Sindhi" }, + { 0x3f, "Tibetan" }, + { 0x40, "Nepali" }, + { 0x41, "Sanskrit" }, + { 0x42, "Marathi" }, + { 0x43, "Bengali" }, + { 0x44, "Assamese" }, + { 0x45, "Gujarati" }, + { 0x46, "Punjabi" }, + { 0x47, "Oriya" }, + { 0x48, "Malayalam" }, + { 0x49, "Kannada" }, + { 0x4a, "Tamil" }, + { 0x4b, "Telugu" }, + { 0x4c, "Sinhala" }, + { 0x4d, "Burmese" }, + { 0x4e, "Khmer" }, + { 0x4f, "Lao" }, + { 0x50, "Vietnamese" }, + { 0x51, "Indonesian" }, + { 0x52, "Tagalog" }, + { 0x53, "MalayRoman" }, + { 0x54, "MalayArabic" }, + { 0x55, "Amharic" }, + { 0x56, "Galla" }, + { 0x57, "Oromo" }, + { 0x58, "Somali" }, + { 0x59, "Swahili" }, + { 0x5a, "Kinyarwanda" }, + { 0x5b, "Rundi" }, + { 0x5c, "Nyanja" }, + { 0x5d, "Malagasy" }, + { 0x5e, "Esperanto" }, + { 0x80, "Welsh" }, + { 0x81, "Basque" }, + { 0x82, "Catalan" }, + { 0x83, "Latin" }, + { 0x84, "Quechua" }, + { 0x85, "Guarani" }, + { 0x86, "Aymara" }, + { 0x87, "Tatar" }, + { 0x88, "Uighur" }, + { 0x89, "Dzongkha" }, + { 0x8a, "JavaneseRom" } +}; + +//! User Date related Information. +extern const TagVocabulary userDatatags[] ={ + { "AllF", "PlayAllFrames" }, + { "CNCV", "CompressorVersion" }, + { "CNFV", "FirmwareVersion" }, + { "CNMN", "Model" }, + { "CNTH", "CanonCNTH" }, + { "DcMD", "DcMD" }, + { "FFMV", "FujiFilmFFMV" }, + { "INFO", "SamsungINFO" }, + { "LOOP", "LoopStyle" }, + { "MMA0", "MinoltaMMA0" }, + { "MMA1", "MinoltaMMA1" }, + { "MVTG", "FujiFilmMVTG" }, + { "NCDT", "NikonNCDT" }, + { "PANA", "PanasonicPANA" }, + { "PENT", "PentaxPENT" }, + { "PXMN", "MakerNotePentax5b" }, + { "PXTH", "PentaxPreview" }, + { "QVMI", "CasioQVMI" }, + { "SDLN", "PlayMode" }, + { "SelO", "PlaySelection" }, + { "TAGS", "KodakTags/KonicaMinoltaTags/MinoltaTags/NikonTags/OlympusTags/PentaxTags/SamsungTags/SanyoMOV/SanyoMP4" }, + { "WLOC", "WindowLocation" }, + { "XMP_", "XMP" }, + { "Xtra", "Xtra" }, + { "hinf", "HintTrackInfo" }, + { "hinv", "HintVersion" }, + { "hnti", "Hint" }, + { "meta", "Meta" }, + { "name", "Name" }, + { "ptv ", "PrintToVideo" }, + { "scrn", "OlympusPreview" }, + { "thmb", "MakerNotePentax5a/OlympusThumbnail" }, +}; + +//! User Data related Information. +extern const TagVocabulary userDataReferencetags[] ={ + { "CNCV", "Xmp.video.CompressorVersion" }, + { "CNFV", "Xmp.video.FirmwareVersion" }, + { "CNMN", "Xmp.video.Model" }, + { "NCHD", "Xmp.video.MakerNoteType" }, + { "WLOC", "Xmp.video.WindowLocation" }, + { "SDLN", "Xmp.video.PlayMode" }, + { "FFMV", "Xmp.video.StreamName" }, + { "SelO", "Xmp.video.PlaySelection" }, + { "name", "Xmp.video.Name" }, + { "vndr", "Xmp.video.Vendor" }, + { " ART", "Xmp.video.Artist" }, + { " alb", "Xmp.video.Album" }, + { " arg", "Xmp.video.Arranger" }, + { " ark", "Xmp.video.ArrangerKeywords" }, + { " cmt", "Xmp.video.Comment" }, + { " cok", "Xmp.video.ComposerKeywords" }, + { " com", "Xmp.video.Composer" }, + { " cpy", "Xmp.video.Copyright" }, + { " day", "Xmp.video.CreateDate" }, + { " dir", "Xmp.video.Director" }, + { " ed1", "Xmp.video.Edit1" }, + { " ed2", "Xmp.video.Edit2" }, + { " ed3", "Xmp.video.Edit3" }, + { " ed4", "Xmp.video.Edit4" }, + { " ed5", "Xmp.video.Edit5" }, + { " ed6", "Xmp.video.Edit6" }, + { " ed7", "Xmp.video.Edit7" }, + { " ed8", "Xmp.video.Edit8" }, + { " ed9", "Xmp.video.Edit9" }, + { " enc", "Xmp.video.Encoder" }, + { " fmt", "Xmp.video.Format" }, + { " gen", "Xmp.video.Genre" }, + { " grp", "Xmp.video.Grouping" }, + { " inf", "Xmp.video.Information" }, + { " isr", "Xmp.video.ISRCCode" }, + { " lab", "Xmp.video.RecordLabelName" }, + { " lal", "Xmp.video.RecordLabelURL" }, + { " lyr", "Xmp.video.Lyrics" }, + { " mak", "Xmp.video.Make" }, + { " mal", "Xmp.video.MakerURL" }, + { " mod", "Xmp.video.Model" }, + { " nam", "Xmp.video.Title" }, + { " pdk", "Xmp.video.ProducerKeywords" }, + { " phg", "Xmp.video.RecordingCopyright" }, + { " prd", "Xmp.video.Producer" }, + { " prf", "Xmp.video.Performers" }, + { " prk", "Xmp.video.PerformerKeywords" }, + { " prl", "Xmp.video.PerformerURL" }, + { " req", "Xmp.video.Requirements" }, + { " snk", "Xmp.video.SubtitleKeywords" }, + { " snm", "Xmp.video.Subtitle" }, + { " src", "Xmp.video.SourceCredits" }, + { " swf", "Xmp.video.SongWriter" }, + { " swk", "Xmp.video.SongWriterKeywords" }, + { " swr", "Xmp.video.SoftwareVersion" }, + { " too", "Xmp.video.Encoder" }, + { " trk", "Xmp.video.Track" }, + { " wrt", "Xmp.video.Composer" }, + { " xyz", "Xmp.video.GPSCoordinates" }, + { "CMbo", "Xmp.video.CameraByteOrder" }, + { "Cmbo", "Xmp.video.CameraByteOrder" }, +}; + +//! Nikon Tags Information. +extern const TagDetails NikonNCTGTags[] ={ + { 0x0001, "Xmp.video.Make" }, + { 0x0002, "Xmp.video.Model" }, + { 0x0003, "Xmp.video.Software" }, + { 0x0011, "Xmp.video.CreationDate" }, + { 0x0012, "Xmp.video.DateTimeOriginal" }, + { 0x0013, "Xmp.video.FrameCount" }, + { 0x0016, "Xmp.video.FrameRate" }, + { 0x0022, "Xmp.video.FrameWidth" }, + { 0x0023, "Xmp.video.FrameHeight" }, + { 0x0032, "Xmp.audio.channelType" }, + { 0x0033, "Xmp.audio.BitsPerSample" }, + { 0x0034, "Xmp.audio.sampleRate" }, + { 0x1108822, "Xmp.video.ExposureProgram" }, + { 0x1109204, "Xmp.video.ExposureCompensation" }, + { 0x1109207, "Xmp.video.MeteringMode" }, + { 0x110a434, "Xmp.video.LensModel" }, + { 0x1200000, "Xmp.video.GPSVersionID" }, + { 0x1200001, "Xmp.video.GPSLatitudeRef" }, + { 0x1200002, "Xmp.video.GPSLatitude" }, + { 0x1200003, "Xmp.video.GPSLongitudeRef" }, + { 0x1200004, "Xmp.video.GPSLongitude" }, + { 0x1200005, "Xmp.video.GPSAltitudeRef" }, + { 0x1200006, "Xmp.video.GPSAltitude" }, + { 0x1200007, "Xmp.video.GPSTimeStamp" }, + { 0x1200008, "Xmp.video.GPSSatellites" }, + { 0x1200010, "Xmp.video.GPSImgDirectionRef" }, + { 0x1200011, "Xmp.video.GPSImgDirection" }, + { 0x1200012, "Xmp.video.GPSMapDatum" }, + { 0x120001d, "Xmp.video.GPSDateStamp" }, + { 0x2000001, "Xmp.video.MakerNoteVersion" }, + { 0x2000005, "Xmp.video.WhiteBalance" }, + { 0x200000b, "Xmp.video.WhiteBalanceFineTune" }, + { 0x200001e, "Xmp.video.ColorSpace" }, + { 0x2000023, "Xmp.video.PictureControlData" }, + { 0x2000024, "Xmp.video.WorldTime" }, + { 0x200002c, "Xmp.video.UnknownInfo" }, + { 0x2000032, "Xmp.video.UnknownInfo2" }, + { 0x2000039, "Xmp.video.LocationInfo" }, + { 0x2000083, "Xmp.video.LensType" }, + { 0x2000084, "Xmp.video.LensModel" }, + { 0x20000ab, "Xmp.video.VariProgram" }, +}; + +//! Nikon Color space Information. +extern const TagDetails NikonColorSpace[] ={ + { 1, "sRGB" }, + { 2, "Adobe RGB" }, +}; + +//! Nikon Tags. +extern const TagVocabulary NikonGPS_Latitude_Longitude_ImgDirection_Reference[] = +{ + { "N", "North" }, + { "S", "South" }, + { "E", "East" }, + { "W", "West" }, + { "M", "Magnetic North" }, + { "T", "True North" }, +}; + +//! Nikon Tags +extern const TagDetails NikonGPSAltitudeRef[] ={ + { 0, "Above Sea Level" }, + { 1, "Below Sea Level" }, +}; + +//! Nikon Tags. +extern const TagDetails NikonExposureProgram[] ={ + { 0, "Not Defined" }, + { 1, "Manual" }, + { 2, "Program AE" }, + { 3, "Aperture-priority AE" }, + { 4, "Shutter speed priority AE" }, + { 5, "Creative (Slow speed)" }, + { 6, "Action (High speed)" }, + { 7, "Portrait" }, + { 8, "Landscape" }, +}; + +//! Nikon Tags. +extern const TagDetails NikonMeteringMode[] ={ + { 0, "Unknown" }, + { 1, "Average" }, + { 2, "Center-weighted average" }, + { 3, "Spot" }, + { 4, "Multi-spot" }, + { 5, "Multi-segment" }, + { 6, "Partial" }, + { 255, "Other" }, +}; + +//! picture tags. +extern const TagDetails PictureControlAdjust[] ={ + { 0, "Default Settings" }, + { 1, "Quick Adjust" }, + { 2, "Full Control" }, +}; + +//! Contrast and Sharpness +extern const TagDetails NormalSoftHard[] ={ + { 0, "Normal" }, + { 1, "Soft" }, + { 2, "Hard" } +}; + +//! Saturation +extern const TagDetails Saturation[] ={ + { 0, "Normal" }, + { 1, "Low" }, + { 2, "High" } +}; + +//! YesNo, used for DaylightSavings +extern const TagDetails YesNo[] ={ + { 0, "No" }, + { 1, "Yes" } +}; + +//! DateDisplayFormat +extern const TagDetails DateDisplayFormat[] ={ + { 0, "Y/M/D" }, + { 1, "M/D/Y" }, + { 2, "D/M/Y" } +}; + +//! Filter Effects. +extern const TagDetails FilterEffect[] ={ + { 0x80, "Off" }, + { 0x81, "Yellow" }, + { 0x82, "Orange" }, + { 0x83, "Red" }, + { 0x84, "Green" }, + { 0xff, "n/a" }, +}; + +//! Toning Effect. +extern const TagDetails ToningEffect[] ={ + { 0x80, "B&W" }, + { 0x81, "Sepia" }, + { 0x82, "Cyanotype" }, + { 0x83, "Red" }, + { 0x84, "Yellow" }, + { 0x85, "Green" }, + { 0x86, "Blue-green" }, + { 0x87, "Blue" }, + { 0x88, "Purple-blue" }, + { 0x89, "Red-purple" }, + { 0xff, "n/a" }, +}; + +//! White balance Information. +extern const TagDetails whiteBalance[] ={ + { 0, "Auto" }, + { 1, "Daylight" }, + { 2, "Shade" }, + { 3, "Fluorescent" }, + { 4, "Tungsten" }, + { 5, "Manual" }, +}; + +//! To select specific bytes with in a chunk. +enum movieHeaderTags{ + MovieHeaderVersion, CreateDate, ModifyDate, TimeScale, Duration, PreferredRate, PreferredVolume, + PreviewTime = 18, PreviewDuration,PosterTime, SelectionTime, SelectionDuration, CurrentTime, NextTrackID +}; + +//! To select specific bytes with in a chunk. +enum trackHeaderTags{ + TrackHeaderVersion, TrackCreateDate, TrackModifyDate, TrackID, TrackDuration = 5, TrackLayer = 8, + TrackVolume, ImageWidth = 19, ImageHeight +}; + +//! To select specific bytes with in a chunk. +enum mediaHeaderTags{ + MediaHeaderVersion, MediaCreateDate, MediaModifyDate, MediaTimeScale, MediaDuration, MediaLanguageCode +}; + +//! To select specific bytes with in a chunk. +enum handlerTags{ + HandlerClass = 1, HandlerType, HandlerVendorID +}; + +//! To select specific bytes with in a chunk. +enum videoHeaderTags{ + GraphicsMode = 2, OpColor +}; + +//! To select specific bytes with in a chunk. +enum stream{ + Video, Audio, Hint, Null, GenMediaHeader +}; + +//! To select specific bytes with in a chunk. +enum imageDescTags{ + codec, VendorID = 4, SourceImageWidth_Height = 7, XResolution, + YResolution, CompressorName = 10, BitDepth +}; + +//! To select specific bytes with in a chunk. +enum audioDescTags{ + AudioFormat, AudioVendorID = 4, AudioChannels, AudioSampleRate = 7, MOV_AudioFormat = 13 +}; + +/*! + * \brief equalsQTimeTag overloaded function to handle tag Array + * It will compare all the tags in a array. + * \param buf Data buffer that will contain Tag to compare. + * \param arr Contains multiple tags to compare from. + * \param arraysize Number of tags in arr. + * \return true if buf matches any one tag in arr. + */ +bool equalsQTimeTag(Exiv2::DataBuf& buf,const char arr[][5],int32_t arraysize) +{ + bool result = false; + for ( int32_t i=0; !result && i< arraysize; i++) + result = (bool)(stricmp((const char*)buf.pData_,arr[i+1])==0); + return result; +} + +/*! + @brief Function used to ignore Tags and values stored in them, + since they are not necessary as metadata information + @param buf Data buffer that will contain Tag to compare + @return Returns true, if Tag is found in the ignoreList[] + */ +bool ignoreList (Exiv2::DataBuf& buf) +{ + const char ignoreList[13][5] ={ + "mdat", "edts", "junk", "iods", "alis", "stsc", "stsz", "stco", "ctts", "stss", + "skip", "wide", "cmvd", }; - extern const TagVocabulary handlerClassTags[] = { - { "dhlr", "Data Handler" }, - { "mhlr", "Media Handler" } + int32_t i; + for(i = 0 ; i < 13 ; ++i) + if(UtilsVideo::compareTagValue(buf, ignoreList[i])) + return true; + + return false; +} + +/*! + @brief Function used to ignore Tags, basically Tags which + contain other tags inside them, since they are not necessary + as metadata information + @param buf Data buffer that will contain Tag to compare + @return Returns true, if Tag is found in the ignoreList[] + */ +bool dataIgnoreList (Exiv2::DataBuf& buf) +{ + const char ignoreList[8][5] ={ + "moov", "mdia", "minf", "dinf", "alis", "stbl", "cmov", + "meta", }; - extern const TagVocabulary handlerTypeTags[] = { - { "alis", "Alias Data" }, - { "crsm", "Clock Reference" }, - { "hint", "Hint Track" }, - { "ipsm", "IPMP" }, - { "m7sm", "MPEG-7 Stream" }, - { "mdir", "Metadata" }, - { "mdta", "Metadata Tags" }, - { "mjsm", "MPEG-J" }, - { "ocsm", "Object Content" }, - { "odsm", "Object Descriptor" }, - { "sdsm", "Scene Description" }, - { "soun", "Audio Track" }, - { "text", "Text" }, - { "tmcd", "Time Code" }, - { "url ", "URL" }, - { "vide", "Video Track" } - }; + int32_t i; + for(i = 0 ; i < 8 ; ++i) + if(UtilsVideo::compareTagValue(buf, ignoreList[i])) + return true; - extern const TagVocabulary vendorIDTags[] = { - { "FFMP", "FFmpeg" }, - { "appl", "Apple" }, - { "olym", "Olympus" }, - { "GIC ", "General Imaging Co." }, - { "fe20", "Olympus (fe20)" }, - { "pana", "Panasonic" }, - { "KMPI", "Konica-Minolta" }, - { "kdak", "Kodak" }, - { "pent", "Pentax" }, - { "NIKO", "Nikon" }, - { "leic", "Leica" }, - { "pr01", "Olympus (pr01)" }, - { "SMI ", "Sorenson Media Inc." }, - { "mino", "Minolta" }, - { "sany", "Sanyo" }, - { "ZORA", "Zoran Corporation" }, - { "niko", "Nikon" } - }; + return false; +} - extern const TagVocabulary cameraByteOrderTags[] = { - { "II", "Little-endian (Intel, II)" }, - { "MM", "Big-endian (Motorola, MM)" } - }; - - extern const TagDetails graphicsModetags[] = { - { 0x0, "srcCopy" }, - { 0x1, "srcOr" }, - { 0x2, "srcXor" }, - { 0x3, "srcBic" }, - { 0x4, "notSrcCopy" }, - { 0x5, "notSrcOr" }, - { 0x6, "notSrcXor" }, - { 0x7, "notSrcBic" }, - { 0x8, "patCopy" }, - { 0x9, "patOr" }, - { 0xa, "patXor" }, - { 0xb, "patBic" }, - { 0xc, "notPatCopy" }, - { 0xd, "notPatOr" }, - { 0xe, "notPatXor" }, - { 0xf, "notPatBic" }, - { 0x20, "blend" }, - { 0x21, "addPin" }, - { 0x22, "addOver" }, - { 0x23, "subPin" }, - { 0x24, "transparent" }, - { 0x25, "addMax" }, - { 0x26, "subOver" }, - { 0x27, "addMin" }, - { 0x31, "grayishTextOr" }, - { 0x32, "hilite" }, - { 0x40, "ditherCopy" }, - { 0x100, "Alpha" }, - { 0x101, "White Alpha" }, - { 0x102, "Pre-multiplied Black Alpha" }, - { 0x110, "Component Alpha" } - }; - - - extern const TagVocabulary userDatatags[] = { - { "AllF", "PlayAllFrames" }, - { "CNCV", "CompressorVersion" }, - { "CNFV", "FirmwareVersion" }, - { "CNMN", "Model" }, - { "CNTH", "CanonCNTH" }, - { "DcMD", "DcMD" }, - { "FFMV", "FujiFilmFFMV" }, - { "INFO", "SamsungINFO" }, - { "LOOP", "LoopStyle" }, - { "MMA0", "MinoltaMMA0" }, - { "MMA1", "MinoltaMMA1" }, - { "MVTG", "FujiFilmMVTG" }, - { "NCDT", "NikonNCDT" }, - { "PANA", "PanasonicPANA" }, - { "PENT", "PentaxPENT" }, - { "PXMN", "MakerNotePentax5b" }, - { "PXTH", "PentaxPreview" }, - { "QVMI", "CasioQVMI" }, - { "SDLN", "PlayMode" }, - { "SelO", "PlaySelection" }, - { "TAGS", "KodakTags/KonicaMinoltaTags/MinoltaTags/NikonTags/OlympusTags/PentaxTags/SamsungTags/SanyoMOV/SanyoMP4" }, - { "WLOC", "WindowLocation" }, - { "XMP_", "XMP" }, - { "Xtra", "Xtra" }, - { "hinf", "HintTrackInfo" }, - { "hinv", "HintVersion" }, - { "hnti", "Hint" }, - { "meta", "Meta" }, - { "name", "Name" }, - { "ptv ", "PrintToVideo" }, - { "scrn", "OlympusPreview" }, - { "thmb", "MakerNotePentax5a/OlympusThumbnail" }, - }; - - extern const TagVocabulary userDataReferencetags[] = { - { "CNCV", "Xmp.video.CompressorVersion" }, - { "CNFV", "Xmp.video.FirmwareVersion" }, - { "CNMN", "Xmp.video.Model" }, - { "NCHD", "Xmp.video.MakerNoteType" }, - { "WLOC", "Xmp.video.WindowLocation" }, - { "SDLN", "Xmp.video.PlayMode" }, - { "FFMV", "Xmp.video.StreamName" }, - { "SelO", "Xmp.video.PlaySelection" }, - { "name", "Xmp.video.Name" }, - { "vndr", "Xmp.video.Vendor" }, - { " ART", "Xmp.video.Artist" }, - { " alb", "Xmp.video.Album" }, - { " arg", "Xmp.video.Arranger" }, - { " ark", "Xmp.video.ArrangerKeywords" }, - { " cmt", "Xmp.video.Comment" }, - { " cok", "Xmp.video.ComposerKeywords" }, - { " com", "Xmp.video.Composer" }, - { " cpy", "Xmp.video.Copyright" }, - { " day", "Xmp.video.CreateDate" }, - { " dir", "Xmp.video.Director" }, - { " ed1", "Xmp.video.Edit1" }, - { " ed2", "Xmp.video.Edit2" }, - { " ed3", "Xmp.video.Edit3" }, - { " ed4", "Xmp.video.Edit4" }, - { " ed5", "Xmp.video.Edit5" }, - { " ed6", "Xmp.video.Edit6" }, - { " ed7", "Xmp.video.Edit7" }, - { " ed8", "Xmp.video.Edit8" }, - { " ed9", "Xmp.video.Edit9" }, - { " enc", "Xmp.video.Encoder" }, - { " fmt", "Xmp.video.Format" }, - { " gen", "Xmp.video.Genre" }, - { " grp", "Xmp.video.Grouping" }, - { " inf", "Xmp.video.Information" }, - { " isr", "Xmp.video.ISRCCode" }, - { " lab", "Xmp.video.RecordLabelName" }, - { " lal", "Xmp.video.RecordLabelURL" }, - { " lyr", "Xmp.video.Lyrics" }, - { " mak", "Xmp.video.Make" }, - { " mal", "Xmp.video.MakerURL" }, - { " mod", "Xmp.video.Model" }, - { " nam", "Xmp.video.Title" }, - { " pdk", "Xmp.video.ProducerKeywords" }, - { " phg", "Xmp.video.RecordingCopyright" }, - { " prd", "Xmp.video.Producer" }, - { " prf", "Xmp.video.Performers" }, - { " prk", "Xmp.video.PerformerKeywords" }, - { " prl", "Xmp.video.PerformerURL" }, - { " req", "Xmp.video.Requirements" }, - { " snk", "Xmp.video.SubtitleKeywords" }, - { " snm", "Xmp.video.Subtitle" }, - { " src", "Xmp.video.SourceCredits" }, - { " swf", "Xmp.video.SongWriter" }, - { " swk", "Xmp.video.SongWriterKeywords" }, - { " swr", "Xmp.video.SoftwareVersion" }, - { " too", "Xmp.video.Encoder" }, - { " trk", "Xmp.video.Track" }, - { " wrt", "Xmp.video.Composer" }, - { " xyz", "Xmp.video.GPSCoordinates" }, - { "CMbo", "Xmp.video.CameraByteOrder" }, - { "Cmbo", "Xmp.video.CameraByteOrder" }, - }; - - extern const TagDetails NikonNCTGTags[] = { - { 0x0001, "Xmp.video.Make" }, - { 0x0002, "Xmp.video.Model" }, - { 0x0003, "Xmp.video.Software" }, - { 0x0011, "Xmp.video.CreationDate" }, - { 0x0012, "Xmp.video.DateTimeOriginal" }, - { 0x0013, "Xmp.video.FrameCount" }, - { 0x0016, "Xmp.video.FrameRate" }, - { 0x0022, "Xmp.video.FrameWidth" }, - { 0x0023, "Xmp.video.FrameHeight" }, - { 0x0032, "Xmp.audio.channelType" }, - { 0x0033, "Xmp.audio.BitsPerSample" }, - { 0x0034, "Xmp.audio.sampleRate" }, - { 0x1108822, "Xmp.video.ExposureProgram" }, - { 0x1109204, "Xmp.video.ExposureCompensation" }, - { 0x1109207, "Xmp.video.MeteringMode" }, - { 0x110a434, "Xmp.video.LensModel" }, - { 0x1200000, "Xmp.video.GPSVersionID" }, - { 0x1200001, "Xmp.video.GPSLatitudeRef" }, - { 0x1200002, "Xmp.video.GPSLatitude" }, - { 0x1200003, "Xmp.video.GPSLongitudeRef" }, - { 0x1200004, "Xmp.video.GPSLongitude" }, - { 0x1200005, "Xmp.video.GPSAltitudeRef" }, - { 0x1200006, "Xmp.video.GPSAltitude" }, - { 0x1200007, "Xmp.video.GPSTimeStamp" }, - { 0x1200008, "Xmp.video.GPSSatellites" }, - { 0x1200010, "Xmp.video.GPSImgDirectionRef" }, - { 0x1200011, "Xmp.video.GPSImgDirection" }, - { 0x1200012, "Xmp.video.GPSMapDatum" }, - { 0x120001d, "Xmp.video.GPSDateStamp" }, - { 0x2000001, "Xmp.video.MakerNoteVersion" }, - { 0x2000005, "Xmp.video.WhiteBalance" }, - { 0x200000b, "Xmp.video.WhiteBalanceFineTune" }, - { 0x200001e, "Xmp.video.ColorSpace" }, - { 0x2000023, "Xmp.video.PictureControlData" }, - { 0x2000024, "Xmp.video.WorldTime" }, - { 0x200002c, "Xmp.video.UnknownInfo" }, - { 0x2000032, "Xmp.video.UnknownInfo2" }, - { 0x2000039, "Xmp.video.LocationInfo" }, - { 0x2000083, "Xmp.video.LensType" }, - { 0x2000084, "Xmp.video.LensModel" }, - { 0x20000ab, "Xmp.video.VariProgram" }, - }; - - extern const TagDetails NikonColorSpace[] = { - { 1, "sRGB" }, - { 2, "Adobe RGB" }, - }; - - extern const TagVocabulary NikonGPS_Latitude_Longitude_ImgDirection_Reference[] = { - { "N", "North" }, - { "S", "South" }, - { "E", "East" }, - { "W", "West" }, - { "M", "Magnetic North" }, - { "T", "True North" }, - }; - - extern const TagDetails NikonGPSAltitudeRef[] = { - { 0, "Above Sea Level" }, - { 1, "Below Sea Level" }, - }; - - extern const TagDetails NikonExposureProgram[] = { - { 0, "Not Defined" }, - { 1, "Manual" }, - { 2, "Program AE" }, - { 3, "Aperture-priority AE" }, - { 4, "Shutter speed priority AE" }, - { 5, "Creative (Slow speed)" }, - { 6, "Action (High speed)" }, - { 7, "Portrait" }, - { 8, "Landscape" }, - }; - - extern const TagDetails NikonMeteringMode[] = { - { 0, "Unknown" }, - { 1, "Average" }, - { 2, "Center-weighted average" }, - { 3, "Spot" }, - { 4, "Multi-spot" }, - { 5, "Multi-segment" }, - { 6, "Partial" }, - { 255, "Other" }, - }; - - extern const TagDetails PictureControlAdjust[] = { - { 0, "Default Settings" }, - { 1, "Quick Adjust" }, - { 2, "Full Control" }, - }; - - //! Contrast and Sharpness - extern const TagDetails NormalSoftHard[] = { - { 0, "Normal" }, - { 1, "Soft" }, - { 2, "Hard" } - }; - - //! Saturation - extern const TagDetails Saturation[] = { - { 0, "Normal" }, - { 1, "Low" }, - { 2, "High" } - }; - - //! YesNo, used for DaylightSavings - extern const TagDetails YesNo[] = { - { 0, "No" }, - { 1, "Yes" } - }; - - //! DateDisplayFormat - extern const TagDetails DateDisplayFormat[] = { - { 0, "Y/M/D" }, - { 1, "M/D/Y" }, - { 2, "D/M/Y" } - }; - - extern const TagDetails FilterEffect[] = { - { 0x80, "Off" }, - { 0x81, "Yellow" }, - { 0x82, "Orange" }, - { 0x83, "Red" }, - { 0x84, "Green" }, - { 0xff, "n/a" }, - }; - - extern const TagDetails ToningEffect[] = { - { 0x80, "B&W" }, - { 0x81, "Sepia" }, - { 0x82, "Cyanotype" }, - { 0x83, "Red" }, - { 0x84, "Yellow" }, - { 0x85, "Green" }, - { 0x86, "Blue-green" }, - { 0x87, "Blue" }, - { 0x88, "Purple-blue" }, - { 0x89, "Red-purple" }, - { 0xff, "n/a" }, - }; - - extern const TagDetails whiteBalance[] = { - { 0, "Auto" }, - { 1, "Daylight" }, - { 2, "Shade" }, - { 3, "Fluorescent" }, - { 4, "Tungsten" }, - { 5, "Manual" }, - }; - - enum movieHeaderTags { - MovieHeaderVersion, CreateDate, ModifyDate, TimeScale, Duration, PreferredRate, PreferredVolume, - PreviewTime = 18, PreviewDuration,PosterTime, SelectionTime, SelectionDuration, CurrentTime, NextTrackID - }; - enum trackHeaderTags { - TrackHeaderVersion, TrackCreateDate, TrackModifyDate, TrackID, TrackDuration = 5, TrackLayer = 8, - TrackVolume, ImageWidth = 19, ImageHeight - }; - enum mediaHeaderTags { - MediaHeaderVersion, MediaCreateDate, MediaModifyDate, MediaTimeScale, MediaDuration, MediaLanguageCode - }; - enum handlerTags { - HandlerClass = 1, HandlerType, HandlerVendorID - }; - enum videoHeaderTags { - GraphicsMode = 2, OpColor - }; - enum stream { - Video, Audio, Hint, Null, GenMediaHeader - }; - enum imageDescTags { - codec, VendorID = 4, SourceImageWidth_Height = 7, XResolution, - YResolution, CompressorName = 10, BitDepth - }; - enum audioDescTags { - AudioFormat, AudioVendorID = 4, AudioChannels, AudioSampleRate = 7, MOV_AudioFormat = 13 - }; - - /*! - @brief Function used to check equality of a Tags with a - particular string (ignores case while comparing). - @param buf Data buffer that will contain Tag to compare - @param str char* Pointer to string - @return Returns true if the buffer value is equal to string. - */ - bool equalsQTimeTag(Exiv2::DataBuf& buf ,const char* str) { - for(int i = 0; i < 4; ++i) - if(tolower(buf.pData_[i]) != tolower(str[i])) - return false; - return true; +/*! + * \brief reverseTagVocabulary: reverse attributed of array elements.To perform reverse + * operation of getting keys from description + * \param inputTagVocabulary + * \param outputTagVocabulary + * \param size + */ +void reverseTagVocabulary(const TagVocabulary inputTagVocabulary[],TagVocabulary outputTagVocabulary[] ,int size) +{ + int32_t i; + for (i=0; i getNumberFromString(const std::string stringData,char seperator ) +{ + int32_t counter = (stringData.size() - 1); + vector shortValues; + int32_t i; + for(i=0; i<2; i++){ + int32_t tmpValueIndex = 3; + Exiv2::byte tmpValue[4] = {}; + while((counter >= 0) && (stringData[counter] != seperator) && (tmpValueIndex >=0)){ + tmpValue[tmpValueIndex] = stringData[counter]; + counter--;tmpValueIndex--; + } + counter--; + shortValues.push_back((int16_t)Exiv2::getShort(tmpValue, bigEndian)); } + return shortValues; +} - /*! - @brief Function used to ignore Tags, basically Tags which - contain other tags inside them, since they are not necessary - as metadata information - @param buf Data buffer that will contain Tag to compare - @return Returns true, if Tag is found in the ignoreList[] - */ - bool dataIgnoreList (Exiv2::DataBuf& buf) { - const char ignoreList[8][5] = { - "moov", "mdia", "minf", "dinf", "alis", "stbl", "cmov", - "meta", - }; - - for(int i = 0 ; i < 8 ; ++i) - if(equalsQTimeTag(buf, ignoreList[i])) - return true; - - return false; +/*! + * \brief getLongFromString functionality is same as above method,with return type + * long vector + * \param stringData: stringdata which is formed by concatinating two distinct + * numerical values + * \param seperator: seperation character like . , etc + * \return + */ +const std::vector getLongFromString(const std::string stringData,char seperator ) +{ + int32_t counter = (stringData.size() - 1); + vector longValues; + for(int32_t i=0; i<2; i++){ + int32_t tmpValueIndex = 3; + Exiv2::byte tmpValue[4]={}; + while((counter >= 0) && (stringData[counter] != seperator) && (tmpValueIndex >=0)){ + tmpValue[tmpValueIndex] = stringData[counter]; + counter--;tmpValueIndex--; + } + counter--; + longValues.push_back((int32_t)Exiv2::getLong(tmpValue, bigEndian)); } + return longValues; +} - /*! - @brief Function used to convert buffer data into 64-bit - signed integer, information stored in Big Endian format - @param buf Data buffer that will contain data to be converted - @return Returns a signed 64-bit integer - */ - int64_t returnBufValue(Exiv2::DataBuf& buf, int n = 4) { - int64_t temp = 0; - for(int i = n - 1; i >= 0; i--) -#ifdef _MSC_VER - temp = temp + static_cast(buf.pData_[i]*(pow(static_cast(256), n-i-1))); +/*! + @brief Function used to convert buffer data into 64-bit + signed integer, information stored in Big Endian format + @param buf Data buffer that will contain data to be converted + @param n + @return Returns a signed 64-bit integer + */ +int64_t returnBufValue(Exiv2::DataBuf& buf, int32_t n = 4) +{ + int64_t temp = 0; + for(int32_t i = n - 1; i >= 0; i--) + temp += + #ifdef _MSC_VER + static_cast(buf.pData_[i]*(pow(256.0, n-i-1))); #else - temp = temp + buf.pData_[i]*(pow((float)256,n-i-1)); + buf.pData_[i]*(pow((float)256,n-i-1)); #endif + return temp; +} - return temp; - } +/*! + * \brief returnBuf: converts integer value to byte value + * which can be written to the file. + * \param intValue + * \param n + * \return + */ +DataBuf returnBuf(int64_t intValue,int32_t n=4) +{ + DataBuf buf((uint32_t)(n+1)); + for(int32_t i = n - 1; i >= 0; i--) + buf.pData_[i] = (Exiv2::byte)(int16_t) ((int32_t)(intValue / (int32_t)pow(256.0,n-i-1)) % 256); + return buf; +} - /*! - @brief Function used to convert buffer data into 64-bit - unsigned integer, information stored in Big Endian format - @param buf Data buffer that will contain data to be converted - @return Returns an unsigned 64-bit integer - */ - uint64_t returnUnsignedBufValue(Exiv2::DataBuf& buf, int n = 4) { - uint64_t temp = 0; - for(int i = n-1; i >= 0; i--) +/*! + @brief Function used to convert buffer data into 64-bit + unsigned integer, information stored in Big Endian format + @param buf Data buffer that will contain data to be converted + @param n + @return Returns an unsigned 64-bit integer + */ +uint64_t returnUnsignedBufValue(Exiv2::DataBuf& buf, int32_t n = 4) +{ + uint64_t temp = 0; + for(int32_t i = n-1; i >= 0; i--) #if _MSC_VER - temp = temp + static_cast(buf.pData_[i]*(pow(static_cast(256), n-i-1))); + temp = temp + static_cast(buf.pData_[i]*(pow(static_cast(256), n-i-1))); #else - temp = temp + buf.pData_[i]*(pow((float)256,n-i-1)); + temp = temp + buf.pData_[i]*(pow((float)256,n-i-1)); #endif - return temp; - } + return temp; +} - /*! - @brief Function used to quicktime files, by checking the - the tags at the start of the file. If the Tag is any one - of the tags listed below, then it is of Quicktime Type. - @param a, b, c, d - characters used to compare - @return Returns true, if Tag is found in the list qTimeTags - */ - bool isQuickTimeType (char a, char b, char c, char d) { - char qTimeTags[][5] = { - "PICT", "free", "ftyp", "junk", "mdat", - "moov", "pict", "pnot", "skip", "uuid", "wide" - }; +/*! + * \brief returnUnsignedBuf converts integer value to byte value + * which can be written to the file. + * \param intValue + * \param n + * \return + */ +DataBuf returnUnsignedBuf(uint64_t intValue,int32_t n=4) +{ + DataBuf buf(n+1); + for(int32_t i = n - 1; i >= 0; i--) + buf.pData_[i] = (Exiv2::byte)(uint16_t) ((int32_t)(intValue / (int32_t)pow(256.0,n-i-1)) % 256); + return buf; +} +/*! + @brief Function used to quicktime files, by checking the + the tags at the start of the file. If the Tag is any one + of the tags listed below, then it is of Quicktime Type. + @param a, b, c, d - characters used to compare + @return Returns true, if Tag is found in the list qTimeTags + */ +bool isQuickTimeType (char a, char b, char c, char d) +{ + char qTimeTags[][5] ={ + "PICT", "free", "ftyp", "junk", "mdat", + "moov", "pict", "pnot", "skip", "uuid", "wide" + }; - for(int i = 0; i <= 10; i++) - if(a == qTimeTags[i][0] && b == qTimeTags[i][1] && c == qTimeTags[i][2] && d == qTimeTags[i][3]) - return true; - return false; - } + int32_t i; + for( i = 0; i <= 10; i++) + if(a == qTimeTags[i][0] && b == qTimeTags[i][1] && c == qTimeTags[i][2] && d == qTimeTags[i][3]) + return true; + return false; +} // isQuickTime +} // namespace Internal +} // namespace Exiv2 -}} // namespace Internal, Exiv2 +namespace Exiv2{ -namespace Exiv2 { +using namespace Exiv2::Internal; - using namespace Exiv2::Internal; - - QuickTimeVideo::QuickTimeVideo(BasicIo::AutoPtr io) - : Image(ImageType::qtime, mdNone, io) - { - } // QuickTimeVideo::QuickTimeVideo - - std::string QuickTimeVideo::mimeType() const - { - return "video/quicktime"; - } - - void QuickTimeVideo::writeMetadata() - { - } - - - void QuickTimeVideo::readMetadata() - { - if (io_->open() != 0) throw Error(9, io_->path(), strError()); - - // Ensure that this is the correct image type - if (!isQTimeType(*io_, false)) { - if (io_->error() || io_->eof()) throw Error(14); - throw Error(3, "QuickTime"); - } - - IoCloser closer(*io_); - clearMetadata(); +class QuickTimeVideo::Private +{ +public: + Private(){ + timeScale_ = 0; + currentStream_ = 0; continueTraversing_ = true; - height_ = width_ = 1; + height_ = 1; + width_ = 1; + m_modifyMetadata = false; + m_decodeMetadata = true; - xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576; - xmpData_["Xmp.video.FileName"] = io_->path(); - xmpData_["Xmp.video.MimeType"] = mimeType(); + decoders.insert(std::make_pair("ftyp",&QuickTimeVideo::fileTypeDecoder)); + decoders.insert(std::make_pair("trak",&QuickTimeVideo::setMediaStream)); + decoders.insert(std::make_pair("mvhd",&QuickTimeVideo::movieHeaderDecoder)); + decoders.insert(std::make_pair("tkhd",&QuickTimeVideo::trackHeaderDecoder)); + decoders.insert(std::make_pair("mdhd",&QuickTimeVideo::mediaHeaderDecoder)); + decoders.insert(std::make_pair("hdlr",&QuickTimeVideo::handlerDecoder)); + decoders.insert(std::make_pair("vmhd",&QuickTimeVideo::videoHeaderDecoder)); + decoders.insert(std::make_pair("udta",&QuickTimeVideo::userDataDecoder)); + decoders.insert(std::make_pair("stsd",&QuickTimeVideo::sampleDesc)); + decoders.insert(std::make_pair("dref",&QuickTimeVideo::multipleEntriesDecoder)); + decoders.insert(std::make_pair("stts",&QuickTimeVideo::timeToSampleDecoder)); + decoders.insert(std::make_pair("pnot",&QuickTimeVideo::previewTagDecoder)); + decoders.insert(std::make_pair("tapt",&QuickTimeVideo::trackApertureTagDecoder)); + decoders.insert(std::make_pair("keys",&QuickTimeVideo::keysTagDecoder)); + } - while (continueTraversing_) decodeBlock(); +public: + //! Variable which stores Time Scale unit, used to calculate time. + uint64_t timeScale_; + //! Variable which stores current stream being processsed. + int currentStream_; + //! Variable to check the end of metadata traversing. + bool continueTraversing_; + //! Variable to store height and width of a video frame. + uint64_t height_, width_; + //! Variable to decide write(True)/read(False) metadata + bool m_modifyMetadata; + //! Variable to decide decode/skip metadata + bool m_decodeMetadata; - aspectRatio(); - } // QuickTimeVideo::readMetadata + std::map decoders; + /*! + * \brief m_QuickSkeleton + * A container which hold the entire information about all premitive atoms inside quicktime + * structure + */ + std::vector m_QuickSkeleton; +}; // class QuickTimeVideo::Private - void QuickTimeVideo::decodeBlock() - { - const long bufMinSize = 4; - DataBuf buf(bufMinSize+1); - unsigned long size = 0; - buf.pData_[4] = '\0' ; +QuickTimeVideo::QuickTimeVideo(BasicIo::AutoPtr io) + : Image(ImageType::qtime, mdNone, io), d(new Private) +{ + d->m_decodeMetadata = true; + d->m_modifyMetadata = false; +} - std::memset(buf.pData_, 0x0, buf.size_); +QuickTimeVideo::~QuickTimeVideo() +{ + delete d; +} - io_->read(buf.pData_, 4); - if(io_->eof()) { - continueTraversing_ = false; - return; +/*! + * \brief QuickTimeVideo::findAtomPositions: + * This method can be called only after read operation,it will return + * list atom(multiple atoms with same atom Id) + * location and atom size,for a given atomId + * \param atomId + * \return + */ +std::vector< pair > QuickTimeVideo::findAtomPositions(const char* atomId) +{ + DataBuf hdrId((uint32_t)5); + hdrId.pData_[4] = '\0'; + + std::vector< pair > atomsDetails; + for (uint32_t i=0; i < d->m_QuickSkeleton.size();i++){ + io_->seek((d->m_QuickSkeleton[i]->m_AtomLocation - 4),BasicIo::beg); + io_->read(hdrId.pData_,4); + if(UtilsVideo::compareTagValue(hdrId,atomId)) + atomsDetails.push_back(make_pair((uint32_t)io_->tell(), + (uint32_t)(d->m_QuickSkeleton[i]->m_AtomSize))); + } + return atomsDetails; +} + +std::string QuickTimeVideo::mimeType() const +{ + return "video/quicktime"; +} + +void QuickTimeVideo::writeMetadata() +{ + if (io_->open() != 0) throw Error(9, io_->path(), strError()); + + IoCloser closer(*io_); + doWriteMetadata(); + io_->close(); +} + +/*! + * \brief QuickTimeVideo::doWriteMetadata + * Search for all the tags(effectively all supported tags in Exiv2) + * present in a file(in m_riffskeleton) and call corresponding handler + * method to write modified metadata. + */ +void QuickTimeVideo::doWriteMetadata() +{ + if (!io_->isopen()) throw Error(20); + + // Ensure that this is the correct image type + if (!isQTimeType(*io_, false)){ + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "QuickTime"); + } + + d->m_decodeMetadata = false; + d->m_modifyMetadata = true; + + std::vector atomFlags; + + //Add new tags to the beginning of the container prmitiveFlags and handle conditions to the end of case statements. + + atomFlags.push_back("stsd"); + atomFlags.push_back("keys"); + atomFlags.push_back("tapt"); + atomFlags.push_back("pnot"); + atomFlags.push_back("udta"); + atomFlags.push_back("vmhd"); + atomFlags.push_back("hdlr"); + atomFlags.push_back("mdhd"); + atomFlags.push_back("tkhd"); + atomFlags.push_back("mvhd"); + atomFlags.push_back("ftyp"); + + uint32_t iMaxCount = atomFlags.size(); + std::vector< pair > trakPositions = findAtomPositions("trak"); + + for (uint32_t j=0; j > atomPositions = findAtomPositions(atomFlags.back().c_str()); + atomFlags.pop_back(); + + for (uint32_t i=0; i< atomPositions.size(); i++){ + if(j == 2 || j == 3 || j == 4 || j == 10){ + io_->seek(trakPositions[i].first,BasicIo::beg); + setMediaStream(0); + } + io_->seek(atomPositions[i].first,BasicIo::beg); + + uint32_t uiAtomPosition = atomPositions[i].second; + switch (j){ + case 0: fileTypeDecoder(uiAtomPosition) ; break; + case 1: movieHeaderDecoder(uiAtomPosition) ; break; + case 2: trackHeaderDecoder(uiAtomPosition) ; break; + case 3: mediaHeaderDecoder(uiAtomPosition) ; break; + case 4: break; + // Fixme:Editing dandler data is known to corrupt file data + // handlerDecoder(hdlrPositions[i].second); + case 5: videoHeaderDecoder(uiAtomPosition) ; break; + case 6: userDataDecoder(uiAtomPosition) ; break; + case 7: previewTagDecoder(uiAtomPosition) ; break; + case 8: trackApertureTagDecoder(uiAtomPosition); break; + case 9:keysTagDecoder(uiAtomPosition) ; break; + case 10: sampleDesc(uiAtomPosition) ; break; + } } + atomPositions.clear(); + } +} - size = Exiv2::getULong(buf.pData_, bigEndian); +void QuickTimeVideo::readMetadata() +{ + if (io_->open() != 0) throw Error(9, io_->path(), strError()); - io_->read(buf.pData_, 4); - if(size < 8) - return; + // Ensure that this is the correct image type + if (!isQTimeType(*io_, false)){ + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "QuickTime"); + } -// std::cerr<<"\nTag=>"<"<continueTraversing_ = true; + d->height_ = d->width_ = 1; - void QuickTimeVideo::tagDecoder(Exiv2::DataBuf &buf, unsigned long size) - { - if (ignoreList(buf)) - discard(size); + xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576; + xmpData_["Xmp.video.FileName"] = io_->path(); + xmpData_["Xmp.video.MimeType"] = mimeType(); - else if (dataIgnoreList(buf)) - decodeBlock(); + while (d->continueTraversing_) decodeBlock(); + aspectRatio(); +} - else if (equalsQTimeTag(buf, "ftyp")) - fileTypeDecoder(size); +void QuickTimeVideo::decodeBlock() +{ + const int32_t bufMinSize = 4; + DataBuf buf(bufMinSize+1); - else if (equalsQTimeTag(buf, "trak")) - setMediaStream(); + io_->read(buf.pData_, 4); + if(io_->eof()){ + d->continueTraversing_ = false; + return; + } - else if (equalsQTimeTag(buf, "mvhd")) - movieHeaderDecoder(size); + uint32_t size = Exiv2::getULong(buf.pData_, bigEndian); + io_->read(buf.pData_, 4); + if(size < 8) return; - else if (equalsQTimeTag(buf, "tkhd")) - trackHeaderDecoder(size); + tagDecoder(buf,size-8); +} - else if (equalsQTimeTag(buf, "mdhd")) - mediaHeaderDecoder(size); +void QuickTimeVideo::tagDecoder(Exiv2::DataBuf &buf, uint32_t size) +{ + const char allAtomFlags[][5]={"ftyp","mvhd","trak","tkhd","mdhd","hdlr","vmhd","udta","dref","stsd","stts","pnot", + "tapt","keys","url ","urn ","dcom","smhd"}; + if(equalsQTimeTag(buf,allAtomFlags,(int)(sizeof(allAtomFlags)/5))){ + QuickAtom* tmpAtom = new QuickAtom(); + tmpAtom->m_AtomLocation = io_->tell(); + tmpAtom->m_AtomSize = size; + memcpy((Exiv2::byte* )tmpAtom->m_AtomId,(const Exiv2::byte*)buf.pData_,5); + d->m_QuickSkeleton.push_back(tmpAtom); + } - else if (equalsQTimeTag(buf, "hdlr")) - handlerDecoder(size); + decFunc decodetIter = d->decoders[std::string(reinterpret_cast(buf.pData_))]; - else if (equalsQTimeTag(buf, "vmhd")) - videoHeaderDecoder(size); + if (ignoreList(buf) ) io_->seek(size, BasicIo::cur); + else if (dataIgnoreList(buf)) decodeBlock(); + else if (decodetIter ) (this->*decodetIter)(size); - else if (equalsQTimeTag(buf, "udta")) - userDataDecoder(size); - - else if (equalsQTimeTag(buf, "dref")) - multipleEntriesDecoder(); - - else if (equalsQTimeTag(buf, "stsd")) - sampleDesc(size); - - else if (equalsQTimeTag(buf, "stts")) - timeToSampleDecoder(); - - else if (equalsQTimeTag(buf, "pnot")) - previewTagDecoder(size); - - else if (equalsQTimeTag(buf, "tapt")) - trackApertureTagDecoder(size); - - else if (equalsQTimeTag(buf, "keys")) - keysTagDecoder(size); - - else if (equalsQTimeTag(buf, "url ")) { - io_->read(buf.pData_, size); - if (currentStream_ == Video) - xmpData_["Xmp.video.URL"] = Exiv2::toString(buf.pData_); - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.URL"] = Exiv2::toString(buf.pData_); + // Decoders with lesser metadata + else if (UtilsVideo::compareTagValue(buf, "url ")){ + if(!d->m_modifyMetadata) readAudVidStrData("URL", size); + else { + if(xmpData_["Xmp.video.URL"].count() > 0) writeStringData(xmpData_["Xmp.video.URL"],size); + else if ((d->currentStream_ == Audio) && (xmpData_["Xmp.audio.URL"].count() >0)) + writeStringData(xmpData_["Xmp.audio.URL"],size); + else io_->seek(size,BasicIo::cur); } - - else if (equalsQTimeTag(buf, "urn ")) { - io_->read(buf.pData_, size); - if (currentStream_ == Video) - xmpData_["Xmp.video.URN"] = Exiv2::toString(buf.pData_); - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.URN"] = Exiv2::toString(buf.pData_); + } + else if (UtilsVideo::compareTagValue(buf, "urn ")){ + if(!d->m_modifyMetadata) readAudVidStrData("URN", size); + else { + if ((d->currentStream_ == Video) && (xmpData_["Xmp.video.URN"].count() >0)) writeStringData(xmpData_["Xmp.video.URN"],size); + else if ((d->currentStream_ == Audio) && (xmpData_["Xmp.audio.URN"].count() >0)) writeStringData(xmpData_["Xmp.audio.URN"],size); + else io_->seek(size,BasicIo::cur); } - - else if (equalsQTimeTag(buf, "dcom")) { + } + else if (UtilsVideo::compareTagValue(buf, "dcom")){ + if(!d->m_modifyMetadata){ io_->read(buf.pData_, size); xmpData_["Xmp.video.Compressor"] = Exiv2::toString(buf.pData_); } - - else if (equalsQTimeTag(buf, "smhd")) { - io_->read(buf.pData_, 4); + else writeStringData(xmpData_["Xmp.video.Compressor"],size); + } + else if (UtilsVideo::compareTagValue(buf, "smhd")){ + io_->seek(4,BasicIo::cur); + if(!d->m_modifyMetadata){ io_->read(buf.pData_, 4); xmpData_["Xmp.audio.Balance"] = returnBufValue(buf, 2); + } else { + DataBuf tmpBuf = returnBuf(xmpData_["Xmp.audio.Balance"].toLong()); + io_->write(tmpBuf.pData_,2); } + } + else io_->seek(size, BasicIo::cur); +} - else { - discard(size); - } - } // QuickTimeVideo::tagDecoder - - void QuickTimeVideo::discard(unsigned long size) - { - uint64_t cur_pos = io_->tell(); - io_->seek(cur_pos + size, BasicIo::beg); - } // QuickTimeVideo::discard - - void QuickTimeVideo::previewTagDecoder(unsigned long size) - { - DataBuf buf(4); - uint64_t cur_pos = io_->tell(); +void QuickTimeVideo::previewTagDecoder(uint32_t size) +{ + DataBuf buf(4); + uint64_t cur_pos = io_->tell(); + if(!d->m_modifyMetadata){ io_->read(buf.pData_, 4); xmpData_["Xmp.video.PreviewDate"] = getULong(buf.pData_, bigEndian); io_->read(buf.pData_, 2); xmpData_["Xmp.video.PreviewVersion"] = getShort(buf.pData_, bigEndian); io_->read(buf.pData_, 4); - if(equalsQTimeTag(buf, "PICT")) + if(UtilsVideo::compareTagValue(buf, "PICT")) xmpData_["Xmp.video.PreviewAtomType"] = "QuickDraw Picture"; else xmpData_["Xmp.video.PreviewAtomType"] = Exiv2::toString(buf.pData_); io_->seek(cur_pos + size, BasicIo::beg); - } // QuickTimeVideo::previewTagDecoder + } else { + writeLongData(xmpData_["Xmp.video.PreviewDate"]); + writeShortData(xmpData_["Xmp.video.PreviewVersion"]); - void QuickTimeVideo::keysTagDecoder(unsigned long size) - { - DataBuf buf(4); - uint64_t cur_pos = io_->tell(); + //Variation + if(xmpData_["Xmp.video.PreviewAtomType"].count() >0){ + Exiv2::byte rawPreviewAtomType[4] = {'P','I','C','T'}; + const std::string previewAtomType = xmpData_["Xmp.video.PreviewAtomType"].toString(); + if(!(previewAtomType.compare("QuickDraw Picture") == 0)) + for(int32_t j=0; j<4; j++) rawPreviewAtomType[j] = previewAtomType[j]; + + writeMultibyte(rawPreviewAtomType, 4); + } + io_->seek(cur_pos + size, BasicIo::beg); + } +} + +void QuickTimeVideo::keysTagDecoder(uint32_t size) +{ + DataBuf buf(4); + uint64_t cur_pos = io_->tell(); + + if(!d->m_modifyMetadata){ io_->read(buf.pData_, 4); xmpData_["Xmp.video.PreviewDate"] = getULong(buf.pData_, bigEndian); io_->read(buf.pData_, 2); xmpData_["Xmp.video.PreviewVersion"] = getShort(buf.pData_, bigEndian); io_->read(buf.pData_, 4); - if(equalsQTimeTag(buf, "PICT")) - xmpData_["Xmp.video.PreviewAtomType"] = "QuickDraw Picture"; - else - xmpData_["Xmp.video.PreviewAtomType"] = Exiv2::toString(buf.pData_); - + if(UtilsVideo::compareTagValue(buf, "PICT")) xmpData_["Xmp.video.PreviewAtomType"] = "QuickDraw Picture"; + else xmpData_["Xmp.video.PreviewAtomType"] = Exiv2::toString(buf.pData_); io_->seek(cur_pos + size, BasicIo::beg); - } // QuickTimeVideo::keysTagDecoder + } else { + writeLongData(xmpData_["Xmp.video.PreviewDate"]); + writeShortData(xmpData_["Xmp.video.PreviewVersion"]); - void QuickTimeVideo::trackApertureTagDecoder(unsigned long size) - { - DataBuf buf(4), buf2(2); - uint64_t cur_pos = io_->tell(); - byte n = 3; + //Variation + if(xmpData_["Xmp.video.PreviewAtomType"].count() >0){ + Exiv2::byte rawPreviewAtomType[4] = {'P','I','C','T'}; + const std::string previewAtomType = xmpData_["Xmp.video.PreviewAtomType"].toString(); + if(!(previewAtomType.compare("QuickDraw Picture") == 0)) + for(int32_t j=0; j<4; j++) + rawPreviewAtomType[j] = previewAtomType[j]; - while(n--) { - io_->seek(static_cast(4), BasicIo::cur); io_->read(buf.pData_, 4); + writeMultibyte(rawPreviewAtomType, 4); + } + io_->seek(cur_pos + size, BasicIo::beg); + } +} - if(equalsQTimeTag(buf, "clef")) { - io_->seek(static_cast(4), BasicIo::cur); +void QuickTimeVideo::trackApertureTagDecoder(uint32_t size) +{ + DataBuf buf(4), buf2(2); + uint64_t cur_pos = io_->tell(); + if(!d->m_modifyMetadata){ + Exiv2::byte n = 3; + while(n--){ + io_->seek(static_cast(4), BasicIo::cur); io_->read(buf.pData_, 4); + + if(UtilsVideo::compareTagValue(buf, "clef")){ + io_->seek(static_cast(4), BasicIo::cur); io_->read(buf.pData_, 2); io_->read(buf2.pData_, 2); - xmpData_["Xmp.video.CleanApertureWidth"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) - + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); + xmpData_["Xmp.video.CleanApertureWidth"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) + + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); io_->read(buf.pData_, 2); io_->read(buf2.pData_, 2); - xmpData_["Xmp.video.CleanApertureHeight"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) - + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); + xmpData_["Xmp.video.CleanApertureHeight"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) + + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); } - - else if(equalsQTimeTag(buf, "prof")) { - io_->seek(static_cast(4), BasicIo::cur); + else if(UtilsVideo::compareTagValue(buf, "prof")){ + io_->seek(static_cast(4), BasicIo::cur); io_->read(buf.pData_, 2); io_->read(buf2.pData_, 2); - xmpData_["Xmp.video.ProductionApertureWidth"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) - + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); + xmpData_["Xmp.video.ProductionApertureWidth"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) + + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); io_->read(buf.pData_, 2); io_->read(buf2.pData_, 2); - xmpData_["Xmp.video.ProductionApertureHeight"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) - + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); + xmpData_["Xmp.video.ProductionApertureHeight"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) + + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); } - - else if(equalsQTimeTag(buf, "enof")) { - io_->seek(static_cast(4), BasicIo::cur); + else if(UtilsVideo::compareTagValue(buf, "enof")){ + io_->seek(static_cast(4), BasicIo::cur); io_->read(buf.pData_, 2); io_->read(buf2.pData_, 2); - xmpData_["Xmp.video.EncodedPixelsWidth"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) - + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); + xmpData_["Xmp.video.EncodedPixelsWidth"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) + + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); io_->read(buf.pData_, 2); io_->read(buf2.pData_, 2); - xmpData_["Xmp.video.EncodedPixelsHeight"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) - + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); + xmpData_["Xmp.video.EncodedPixelsHeight"] = Exiv2::toString(getUShort(buf.pData_, bigEndian)) + + "." + Exiv2::toString(getUShort(buf2.pData_, bigEndian)); } } - io_->seek(static_cast(cur_pos + size), BasicIo::beg); - } // QuickTimeVideo::trackApertureTagDecoder + io_->seek(static_cast(cur_pos + size), BasicIo::beg); + } else { + Exiv2::byte n = 3; + while(n--){ + io_->seek(static_cast(4), BasicIo::cur); io_->read(buf.pData_, 4); - void QuickTimeVideo::CameraTagsDecoder(unsigned long size_external) - { - uint64_t cur_pos = io_->tell(); - DataBuf buf(50), buf2(4); - const TagDetails* td; + if(UtilsVideo::compareTagValue(buf, "clef")){ + io_->seek(static_cast(4), BasicIo::cur); + writeApertureData(xmpData_["Xmp.video.CleanApertureWidth"],4); + writeApertureData(xmpData_["Xmp.video.CleanApertureHeight"],4); + } + else if(UtilsVideo::compareTagValue(buf, "prof")){ + io_->seek(static_cast(4), BasicIo::cur); + writeApertureData(xmpData_["Xmp.video.ProductionApertureWidth"],4); + writeApertureData(xmpData_["Xmp.video.ProductionApertureHeight"],4); + } + else if(UtilsVideo::compareTagValue(buf, "enof")){ + io_->seek(static_cast(4), BasicIo::cur); + writeApertureData(xmpData_["Xmp.video.EncodedPixelsWidth"],4); + writeApertureData(xmpData_["Xmp.video.EncodedPixelsHeight"],4); + } + } + io_->seek(static_cast(cur_pos + size), BasicIo::beg); + } +} - io_->read(buf.pData_, 4); - if(equalsQTimeTag(buf, "NIKO")) { - io_->seek(cur_pos, BasicIo::beg); - - io_->read(buf.pData_, 24); - xmpData_["Xmp.video.Make"] = Exiv2::toString(buf.pData_); - io_->read(buf.pData_, 14); - xmpData_["Xmp.video.Model"] = Exiv2::toString(buf.pData_); +void QuickTimeVideo::CameraTagsDecoder(uint32_t size_external) +{ + uint64_t cur_pos = io_->tell(); + DataBuf buf(50), buf2(4); + const TagDetails* td; + const RevTagDetails* rtd; + io_->read(buf.pData_, 4); + if(UtilsVideo::compareTagValue(buf, "NIKO")){ + io_->seek(cur_pos, BasicIo::beg); + if(!d->m_modifyMetadata){ + readStrData("Xmp.video.Make", 24); + readStrData("Xmp.video.Model", 14); io_->read(buf.pData_, 4); xmpData_["Xmp.video.ExposureTime"] = "1/" + Exiv2::toString( ceil( getULong(buf.pData_, littleEndian) / (double)10)); - io_->read(buf.pData_, 4); io_->read(buf2.pData_, 4); - xmpData_["Xmp.video.FNumber"] = getULong(buf.pData_, littleEndian) / (double)getULong(buf2.pData_, littleEndian) ; - io_->read(buf.pData_, 4); io_->read(buf2.pData_, 4); + io_->read(buf.pData_, 4); + io_->read(buf2.pData_, 4); + xmpData_["Xmp.video.FNumber"] = getULong(buf.pData_, littleEndian) / (double)getULong(buf2.pData_, littleEndian) ; + io_->read(buf.pData_, 4); + io_->read(buf2.pData_, 4); xmpData_["Xmp.video.ExposureCompensation"] = getULong(buf.pData_, littleEndian) / (double)getULong(buf2.pData_, littleEndian) ; - io_->read(buf.pData_, 10); io_->read(buf.pData_, 4); + io_->read(buf.pData_, 10); + io_->read(buf.pData_, 4); td = find(whiteBalance, getULong(buf.pData_, littleEndian)); - if (td) - xmpData_["Xmp.video.WhiteBalance"] = exvGettext(td->label_); - io_->read(buf.pData_, 4); io_->read(buf2.pData_, 4); - xmpData_["Xmp.video.FocalLength"] = getULong(buf.pData_, littleEndian) / (double)getULong(buf2.pData_, littleEndian) ; - io_->seek(static_cast(95), BasicIo::cur); - io_->read(buf.pData_, 48); - xmpData_["Xmp.video.Software"] = Exiv2::toString(buf.pData_); + if (td) xmpData_["Xmp.video.WhiteBalance"] = exvGettext(td->label_); + io_->read(buf.pData_, 4); + io_->read(buf2.pData_, 4); + xmpData_["Xmp.video.FocalLength"] = getULong(buf.pData_, littleEndian) / (double)getULong(buf2.pData_, littleEndian) ; + io_->seek(static_cast(95), BasicIo::cur); + readStrData("Xmp.video.Software", 48); io_->read(buf.pData_, 4); xmpData_["Xmp.video.ISO"] = getULong(buf.pData_, littleEndian); + io_->seek(cur_pos + size_external, BasicIo::beg); + } else { + bool bDataWritten = false; + RevTagDetails revTagDetails[(sizeof(whiteBalance)/sizeof(whiteBalance[0]))]; + reverseTagDetails(whiteBalance,revTagDetails,((sizeof(whiteBalance)/sizeof(whiteBalance[0])))); + + writeShortData(xmpData_["Xmp.video.Make"],24); + writeShortData(xmpData_["Xmp.video.Model"],24); + + //Variation + if(xmpData_["Xmp.video.ExposureTime"].count() >0){ + const std::vector d_exposureTime = + getLongFromString(xmpData_["Xmp.video.ExposureTime"].toString(),'/'); + const int32_t tmpValue = (d_exposureTime.at(1)*10); + io_->write((Exiv2::byte*)&tmpValue,4); + } + else io_->seek(4,BasicIo::cur); + + //Variation + if(xmpData_["Xmp.video.FNumber"].count() >0){ + io_->seek(4,BasicIo::cur); + io_->read(buf2.pData_,4); + io_->seek(-8,BasicIo::cur); + const int32_t fNumber =(int32_t) + ((double)xmpData_["Xmp.video.FNumber"].toLong() + *(double)getULong(buf2.pData_, littleEndian)); + writeMultibyte((Exiv2::byte*)&fNumber, 4, 4); + } + else io_->seek(8,BasicIo::cur); + + if(xmpData_["Xmp.video.ExposureCompensation"].count() >0){ + io_->seek(4,BasicIo::cur); + io_->read(buf2.pData_,4); + io_->seek(-8,BasicIo::cur); + const int32_t exposureCompensation =(int32_t) + ((double)xmpData_["Xmp.video.ExposureCompensation"].toLong() + *(double)getULong(buf2.pData_, littleEndian)); + writeMultibyte((Exiv2::byte*)&exposureCompensation, 4, 14); + } + else io_->seek(18,BasicIo::cur); + + if(xmpData_["Xmp.video.WhiteBalance"].count() >0){ + rtd = find(revTagDetails,xmpData_["Xmp.video.WhiteBalance"].toString()); + if(rtd){ + const int32_t sWhiteBalance = (int32_t)rtd->val_; + bDataWritten = writeMultibyte((Exiv2::byte*)&sWhiteBalance,4); + } + } + if(!bDataWritten) io_->seek(4,BasicIo::cur); + + if(xmpData_["Xmp.video.FocalLength"].count() >0){ + io_->seek(4,BasicIo::cur); + io_->read(buf2.pData_,4); + io_->seek(-8,BasicIo::cur); + const int32_t focalLength =(int32_t)((double)xmpData_["Xmp.video.FocalLength"].toLong() + *(double)getULong(buf2.pData_, littleEndian)); + writeMultibyte((Exiv2::byte*)&focalLength, 4, 99); + } + else io_->seek(103,BasicIo::cur); + + writeStringData(xmpData_["Xmp.video.Software"],48); + writeLongData(xmpData_["Xmp.video.ISO"]); } io_->seek(cur_pos + size_external, BasicIo::beg); - } // QuickTimeVideo::CameraTagsDecoder + } +} - void QuickTimeVideo::userDataDecoder(unsigned long size_external) - { - uint64_t cur_pos = io_->tell(); - const TagVocabulary* td; - const TagVocabulary* tv, *tv_internal; - - const long bufMinSize = 100; - DataBuf buf(bufMinSize); - unsigned long size = 0, size_internal = size_external; - std::memset(buf.pData_, 0x0, buf.size_); - - while((size_internal/4 != 0) && (size_internal > 0)) { +void QuickTimeVideo::userDataDecoder(uint32_t size_external) +{ + uint64_t cur_pos = io_->tell(); + const TagVocabulary* td; + const TagVocabulary* tv; + const TagVocabulary* tv_internal; + const int32_t bufMinSize = 100; + DataBuf buf(bufMinSize); + uint32_t size = 0; + uint32_t size_internal = size_external; + if(!d->m_modifyMetadata){ + while((size_internal/4 != 0) && (size_internal > 0)){ buf.pData_[4] = '\0' ; io_->read(buf.pData_, 4); size = Exiv2::getULong(buf.pData_, bigEndian); - if(size > size_internal) - break; + if(size > size_internal) break; size_internal -= size; io_->read(buf.pData_, 4); - if(buf.pData_[0] == 169) - buf.pData_[0] = ' '; + if(buf.pData_[0] == 169) buf.pData_[0] = ' '; td = find(userDatatags, Exiv2::toString( buf.pData_)); tv = find(userDataReferencetags, Exiv2::toString( buf.pData_)); - if(size == 0 || (size - 12) <= 0) - break; - - else if(equalsQTimeTag(buf, "DcMD") || equalsQTimeTag(buf, "NCDT")) - userDataDecoder(size - 8); - - else if(equalsQTimeTag(buf, "NCTG")) - NikonTagsDecoder(size - 8); - - else if(equalsQTimeTag(buf, "TAGS")) - CameraTagsDecoder(size - 8); - - else if(equalsQTimeTag(buf, "CNCV") || equalsQTimeTag(buf, "CNFV") - || equalsQTimeTag(buf, "CNMN") || equalsQTimeTag(buf, "NCHD") - || equalsQTimeTag(buf, "FFMV")) { - io_->read(buf.pData_, size - 8); - xmpData_[exvGettext(tv->label_)] = Exiv2::toString(buf.pData_); + if (size == 0 || (size - 12) <= 0) break; + else if(UtilsVideo::compareTagValue(buf, "DcMD") || UtilsVideo::compareTagValue(buf, "NCDT")) userDataDecoder(size - 8); + else if(UtilsVideo::compareTagValue(buf, "NCTG")) NikonTagsDecoder(size - 8); + else if(UtilsVideo::compareTagValue(buf, "TAGS")) CameraTagsDecoder(size - 8); + else if(UtilsVideo::compareTagValue(buf, "CNCV") || UtilsVideo::compareTagValue(buf, "CNFV") + || UtilsVideo::compareTagValue(buf, "CNMN") || UtilsVideo::compareTagValue(buf, "NCHD") + || UtilsVideo::compareTagValue(buf, "FFMV")){ + readStrData((std::string)exvGettext(tv->label_) , size - 8); } - - else if(equalsQTimeTag(buf, "CMbo") || equalsQTimeTag(buf, "Cmbo")) { + else if(UtilsVideo::compareTagValue(buf, "CMbo") || UtilsVideo::compareTagValue(buf, "Cmbo")){ io_->read(buf.pData_, 2); buf.pData_[2] = '\0' ; tv_internal = find(cameraByteOrderTags, Exiv2::toString( buf.pData_)); - if (tv_internal) - xmpData_[exvGettext(tv->label_)] = exvGettext(tv_internal->label_); - else - xmpData_[exvGettext(tv->label_)] = Exiv2::toString(buf.pData_); + if (tv_internal) xmpData_[exvGettext(tv->label_)] = exvGettext(tv_internal->label_); + else xmpData_[exvGettext(tv->label_)] = Exiv2::toString(buf.pData_); } - - else if(tv) { - io_->read(buf.pData_, 4); - io_->read(buf.pData_, size-12); + else if(tv){ + io_->read(buf.pData_, size-8); xmpData_[exvGettext(tv->label_)] = Exiv2::toString(buf.pData_); } - - else if(td) - tagDecoder(buf,size-8); + else if(td) tagDecoder(buf,size-8); } - io_->seek(cur_pos + size_external, BasicIo::beg); - } // QuickTimeVideo::userDataDecoder + } else { + while((size_internal/4 != 0) && (size_internal > 0)){ + buf.pData_[4] = '\0' ; + io_->read(buf.pData_, 4); + size = Exiv2::getULong(buf.pData_, bigEndian); + if(size > size_internal) break; + size_internal -= size; + io_->read(buf.pData_, 4); + if(buf.pData_[0] == 169) buf.pData_[0] = ' '; + td = find(userDatatags, Exiv2::toString( buf.pData_)); + tv = find(userDataReferencetags, Exiv2::toString( buf.pData_)); + if (size == 0 || (size - 12) <= 0) break; // size <= 12? + else if(UtilsVideo::compareTagValue(buf, "DcMD") || UtilsVideo::compareTagValue(buf, "NCDT")) userDataDecoder(size - 8); + else if(UtilsVideo::compareTagValue(buf, "NCTG")) NikonTagsDecoder(size - 8); + else if(UtilsVideo::compareTagValue(buf, "TAGS")) CameraTagsDecoder(size - 8); + else if(UtilsVideo::compareTagValue(buf, "CNCV") || UtilsVideo::compareTagValue(buf, "CNFV") + || UtilsVideo::compareTagValue(buf, "CNMN") || UtilsVideo::compareTagValue(buf, "NCHD") + || UtilsVideo::compareTagValue(buf, "FFMV") + ) writeShortData(xmpData_[exvGettext(tv->label_)],(size-8)); + else if(UtilsVideo::compareTagValue(buf, "CMbo") || UtilsVideo::compareTagValue(buf, "Cmbo")) io_->seek(2,BasicIo::cur); + else if(tv) writeShortData(xmpData_[exvGettext(tv->label_)],(size-8)); + } + io_->seek(cur_pos + size_external, BasicIo::beg); + } +} - void QuickTimeVideo::NikonTagsDecoder(unsigned long size_external) - { - uint64_t cur_pos = io_->tell(); - DataBuf buf(200), buf2(4+1); - unsigned long TagID = 0; - unsigned short dataLength = 0, dataType = 2; - const TagDetails* td, *td2; +void QuickTimeVideo::NikonTagsDecoder(uint32_t size_external) +{ + uint64_t cur_pos = io_->tell(); + DataBuf buf(200); + DataBuf buf2(4+1); + uint64_t TagID = 0 ; + uint16_t dataLength = 0 ; + uint16_t dataType = 2 ; + const TagDetails* td ; + const TagDetails* td2 ; + const RevTagDetails* rtd2; - for(int i = 0 ; i < 100 ; i++) { + if(!d->m_modifyMetadata){ + for(int32_t i = 0 ; i < 100 ; i++){ + io_->read(buf.pData_, 4); + TagID = Exiv2::getULong(buf.pData_, bigEndian); + td = find(NikonNCTGTags, TagID); + + io_->read(buf.pData_, 2); + dataType = Exiv2::getUShort(buf.pData_, bigEndian); + + io_->read(buf.pData_, 2); + + if(TagID == 0x2000023){ + uint64_t local_pos = io_->tell(); + dataLength = Exiv2::getUShort(buf.pData_, bigEndian); + std::memset(buf.pData_, 0x0, buf.size_); + + io_->read(buf.pData_, 4); xmpData_["Xmp.video.PictureControlVersion"] = Exiv2::toString(buf.pData_); + io_->read(buf.pData_, 20); xmpData_["Xmp.video.PictureControlName"] = Exiv2::toString(buf.pData_); + io_->read(buf.pData_, 20); xmpData_["Xmp.video.PictureControlBase"] = Exiv2::toString(buf.pData_); + io_->read(buf.pData_, 4); + std::memset(buf.pData_, 0x0, buf.size_); + + io_->read(buf.pData_, 1); + td2 = find(PictureControlAdjust, (int)buf.pData_[0] & 7 ); + if(td2) xmpData_["Xmp.video.PictureControlAdjust"] = exvGettext(td2->label_); + else xmpData_["Xmp.video.PictureControlAdjust"] = (int)buf.pData_[0] & 7 ; + + io_->read(buf.pData_, 1); + td2 = find(NormalSoftHard, (int)buf.pData_[0] & 7 ); + if(td2) xmpData_["Xmp.video.PictureControlQuickAdjust"] = exvGettext(td2->label_); + + io_->read(buf.pData_, 1); + td2 = find(NormalSoftHard, (int)buf.pData_[0] & 7 ); + if(td2) xmpData_["Xmp.video.Sharpness"] = exvGettext(td2->label_); + else xmpData_["Xmp.video.Sharpness"] = (int)buf.pData_[0] & 7; + + io_->read(buf.pData_, 1); + td2 = find(NormalSoftHard, (int)buf.pData_[0] & 7 ); + if(td2) xmpData_["Xmp.video.Contrast"] = exvGettext(td2->label_); + else xmpData_["Xmp.video.Contrast"] = (int)buf.pData_[0] & 7; + + io_->read(buf.pData_, 1); + td2 = find(NormalSoftHard, (int)buf.pData_[0] & 7 ); + if(td2) xmpData_["Xmp.video.Brightness"] = exvGettext(td2->label_); + else xmpData_["Xmp.video.Brightness"] = (int)buf.pData_[0] & 7; + + io_->read(buf.pData_, 1); + td2 = find(Saturation, (int)buf.pData_[0] & 7 ); + if(td2) xmpData_["Xmp.video.Saturation"] = exvGettext(td2->label_); + else xmpData_["Xmp.video.Saturation"] = (int)buf.pData_[0] & 7; + + io_->read(buf.pData_, 1); + xmpData_["Xmp.video.HueAdjustment"] = (int)buf.pData_[0] & 7; + + io_->read(buf.pData_, 1); + td2 = find(FilterEffect, (int)buf.pData_[0]); + if(td2) xmpData_["Xmp.video.FilterEffect"] = exvGettext(td2->label_); + else xmpData_["Xmp.video.FilterEffect"] = (int)buf.pData_[0]; + + io_->read(buf.pData_, 1); + td2 = find(ToningEffect, (int)buf.pData_[0]); + if(td2) xmpData_["Xmp.video.ToningEffect"] = exvGettext(td2->label_); + else xmpData_["Xmp.video.ToningEffect"] = (int)buf.pData_[0]; + io_->read(buf.pData_, 1); xmpData_["Xmp.video.ToningSaturation"] = (int)buf.pData_[0]; + io_->seek(local_pos + dataLength, BasicIo::beg); + } + else if(TagID == 0x2000024){ + uint64_t local_pos = io_->tell(); + dataLength = Exiv2::getUShort(buf.pData_, bigEndian); + std::memset(buf.pData_, 0x0, buf.size_); + + io_->read(buf.pData_, 2); + xmpData_["Xmp.video.TimeZone"] = Exiv2::getShort(buf.pData_, bigEndian); + io_->read(buf.pData_, 1); + td2 = find(YesNo, (int)buf.pData_[0]); + if(td2) xmpData_["Xmp.video.DayLightSavings"] = exvGettext(td2->label_); + + io_->read(buf.pData_, 1); + td2 = find(DateDisplayFormat, (int)buf.pData_[0]); + if(td2) xmpData_["Xmp.video.DateDisplayFormat"] = exvGettext(td2->label_); + + io_->seek(local_pos + dataLength, BasicIo::beg); + } + else if(dataType == 2 || dataType == 7){ + dataLength = Exiv2::getUShort(buf.pData_, bigEndian); + std::memset(buf.pData_, 0x0, buf.size_); + + // Sanity check with an "unreasonably" large number + if (dataLength > 200){ +#ifndef SUPPRESS_WARNINGS + EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be larger than 200." + << " Entries considered invalid. Not Processed.\n"; +#endif + io_->seek(io_->tell() + dataLength, BasicIo::beg); + } + else io_->read(buf.pData_, dataLength); + + if(td) xmpData_[exvGettext(td->label_)] = Exiv2::toString(buf.pData_); + } + else if(dataType == 4){ + dataLength = Exiv2::getUShort(buf.pData_, bigEndian) * 4; + std::memset(buf.pData_, 0x0, buf.size_); + io_->read(buf.pData_, 4); + if(td) xmpData_[exvGettext(td->label_)] = Exiv2::toString(Exiv2::getULong( buf.pData_, bigEndian)); + + // Sanity check with an "unreasonably" large number + if (dataLength > 200 || dataLength < 4){ +#ifndef SUPPRESS_WARNINGS + EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be of inapropriate size." + << " Entries considered invalid. Not Processed.\n"; +#endif + io_->seek(io_->tell() + dataLength - 4, BasicIo::beg); + } + else io_->read(buf.pData_, dataLength - 4); + } + else if(dataType == 3){ + dataLength = Exiv2::getUShort(buf.pData_, bigEndian) * 2; + std::memset(buf.pData_, 0x0, buf.size_); + io_->read(buf.pData_, 2); + if(td) xmpData_[exvGettext(td->label_)] = Exiv2::toString(Exiv2::getUShort( buf.pData_, bigEndian)); + + // Sanity check with an "unreasonably" large number + if (dataLength > 200 || dataLength < 2){ +#ifndef SUPPRESS_WARNINGS + EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be of inapropriate size." + << " Entries considered invalid. Not Processed.\n"; +#endif + io_->seek(io_->tell() + dataLength - 2, BasicIo::beg); + } + else io_->read(buf.pData_, dataLength - 2); + } + else if(dataType == 5){ + dataLength = Exiv2::getUShort(buf.pData_, bigEndian) * 8; + std::memset(buf.pData_, 0x0, buf.size_); + io_->read(buf.pData_, 4); + io_->read(buf2.pData_, 4); + if(td) xmpData_[exvGettext(td->label_)] = Exiv2::toString((double)Exiv2::getULong( buf.pData_, bigEndian) + / (double)Exiv2::getULong( buf2.pData_, bigEndian)); + + // Sanity check with an "unreasonably" large number + if (dataLength > 200 || dataLength < 8){ +#ifndef SUPPRESS_WARNINGS + EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be of inapropriate size." + << " Entries considered invalid. Not Processed.\n"; +#endif + io_->seek(io_->tell() + dataLength - 8, BasicIo::beg); + } + else io_->read(buf.pData_, dataLength - 8); + } + else if(dataType == 8){ + dataLength = Exiv2::getUShort(buf.pData_, bigEndian) * 2; + std::memset(buf.pData_, 0x0, buf.size_); + io_->read(buf.pData_, 2); + io_->read(buf2.pData_, 2); + if(td) xmpData_[exvGettext(td->label_)] = Exiv2::toString(Exiv2::getUShort( buf.pData_, bigEndian) ) + + " " + Exiv2::toString(Exiv2::getUShort( buf2.pData_, bigEndian)); + + // Sanity check with an "unreasonably" large number + if (dataLength > 200 || dataLength < 4){ +#ifndef SUPPRESS_WARNINGS + EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be of inapropriate size." + << " Entries considered invalid. Not Processed.\n"; +#endif + io_->seek(io_->tell() + dataLength - 4, BasicIo::beg); + } + else io_->read(buf.pData_, dataLength - 4); + } + } + io_->seek(cur_pos + size_external, BasicIo::beg); + } else { + RevTagDetails revNikonNCTGTags[(sizeof(NikonNCTGTags)/sizeof(NikonNCTGTags[0]))]; + reverseTagDetails(NikonNCTGTags,revNikonNCTGTags,((sizeof(NikonNCTGTags)/sizeof(NikonNCTGTags[0])))); + + bool bDataWriten = false; + for(int32_t i = 0 ; i < 100 ; i++){ io_->read(buf.pData_, 4); TagID = Exiv2::getULong(buf.pData_, bigEndian); td = find(NikonNCTGTags, TagID); @@ -963,691 +1639,1273 @@ namespace Exiv2 { std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 2); - if(TagID == 0x2000023) { + if(TagID == 0x2000023){ + uint64_t local_pos = io_->tell(); + dataLength = Exiv2::getUShort(buf.pData_, bigEndian); + writeShortData(xmpData_["Xmp.video.PictureControlVersion"],4); + writeShortData(xmpData_["Xmp.video.PictureControlName"],20); + writeShortData(xmpData_["Xmp.video.PictureControlBase"],20); + io_->seek(4,BasicIo::cur); + std::memset(buf.pData_, 0x0, buf.size_); + + if(xmpData_["Xmp.video.PictureControlAdjust"].count() >0){ + RevTagDetails revTagDetails[(sizeof(PictureControlAdjust)/sizeof(PictureControlAdjust[0]))]; + reverseTagDetails(PictureControlAdjust,revTagDetails,((sizeof(PictureControlAdjust)/sizeof(PictureControlAdjust[0])))); + + rtd2 = find(revTagDetails,xmpData_["Xmp.video.PictureControlAdjust"].toString()); + if(rtd2){ + Exiv2::byte rawPictureControlAdjust = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawPictureControlAdjust, 1); + } + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.video.PictureControlQuickAdjust"].count() >0){ + RevTagDetails revTagDetails[(sizeof(NormalSoftHard)/sizeof(NormalSoftHard[0]))]; + reverseTagDetails(NormalSoftHard,revTagDetails,((sizeof(NormalSoftHard)/sizeof(NormalSoftHard[0])))); + + rtd2 = find(revTagDetails, xmpData_["Xmp.video.PictureControlQuickAdjust"].toString() ); + if(rtd2){ + Exiv2::byte rawPictureControlQuickAdjust = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawPictureControlQuickAdjust,1); + } + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.video.Sharpness"].count() >0){ + RevTagDetails revTagDetails[(sizeof(NormalSoftHard)/sizeof(NormalSoftHard[0]))]; + reverseTagDetails(NormalSoftHard,revTagDetails,((sizeof(NormalSoftHard)/sizeof(NormalSoftHard[0])))); + + rtd2 = find(revTagDetails, xmpData_["Xmp.video.Sharpness"].toString() ); + if(rtd2){ + Exiv2::byte rawSharpness = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawSharpness,1); + } + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.video.Contrast"].count() >0){ + RevTagDetails revTagDetails[(sizeof(NormalSoftHard)/sizeof(NormalSoftHard[0]))]; + reverseTagDetails(NormalSoftHard,revTagDetails,((sizeof(NormalSoftHard)/sizeof(NormalSoftHard[0])))); + + rtd2 = find(revTagDetails, xmpData_["Xmp.video.Contrast"].toString() ); + if(rtd2){ + Exiv2::byte rawContrast = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawContrast,1); + } + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.video.Brightness"].count() >0){ + RevTagDetails revTagDetails[(sizeof(NormalSoftHard)/sizeof(NormalSoftHard[0]))]; + reverseTagDetails(NormalSoftHard,revTagDetails,((sizeof(NormalSoftHard)/sizeof(NormalSoftHard[0])))); + + rtd2 = find(revTagDetails, xmpData_["Xmp.video.Brightness"].toString() ); + if(rtd2){ + Exiv2::byte rawBrightness = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawBrightness,1); + } + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.video.Saturation"].count() >0){ + RevTagDetails revTagDetails[(sizeof(Saturation)/sizeof(Saturation[0]))]; + reverseTagDetails(Saturation,revTagDetails,((sizeof(Saturation)/sizeof(Saturation[0])))); + + rtd2 = find(revTagDetails, xmpData_["Xmp.video.Saturation"].toString() ); + if(rtd2){ + Exiv2::byte rawSaturation = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawSaturation,1); + } + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.video.HueAdjustment"].count() >0){ + Exiv2::byte rawHueAdjustment = (Exiv2::byte)xmpData_["Xmp.video.HueAdjustment"].toString()[0]; + bDataWriten = writeMultibyte(&rawHueAdjustment,1); + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.video.FilterEffect"].count() >0){ + RevTagDetails revTagDetails[(sizeof(FilterEffect)/sizeof(FilterEffect[0]))]; + reverseTagDetails(FilterEffect,revTagDetails,((sizeof(FilterEffect)/sizeof(FilterEffect[0])))); + + rtd2 = find(revTagDetails, xmpData_["Xmp.video.FilterEffect"].toString() ); + if(rtd2){ + Exiv2::byte rawFilterEffect = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawFilterEffect,1); + } + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.video.ToningEffect"].count() >0){ + RevTagDetails revTagDetails[(sizeof(ToningEffect)/sizeof(ToningEffect[0]))]; + reverseTagDetails(ToningEffect,revTagDetails,((sizeof(ToningEffect)/sizeof(ToningEffect[0])))); + + rtd2 = find(revTagDetails, xmpData_["Xmp.video.ToningEffect"].toString() ); + if(rtd2){ + Exiv2::byte rawToningEffect = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawToningEffect,1); + } + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.video.ToningSaturation"].count() >0){ + Exiv2::byte rawToningSaturation = (Exiv2::byte)xmpData_["Xmp.video.ToningSaturation"].toString()[0]; + bDataWriten = writeMultibyte(&rawToningSaturation,1); + } + io_->seek(local_pos + dataLength, BasicIo::beg); + } + else if(TagID == 0x2000024){ uint64_t local_pos = io_->tell(); dataLength = Exiv2::getUShort(buf.pData_, bigEndian); std::memset(buf.pData_, 0x0, buf.size_); - io_->read(buf.pData_, 4); xmpData_["Xmp.video.PictureControlVersion"] = Exiv2::toString(buf.pData_); - io_->read(buf.pData_, 20); xmpData_["Xmp.video.PictureControlName"] = Exiv2::toString(buf.pData_); - io_->read(buf.pData_, 20); xmpData_["Xmp.video.PictureControlBase"] = Exiv2::toString(buf.pData_); - io_->read(buf.pData_, 4); std::memset(buf.pData_, 0x0, buf.size_); + writeShortData(xmpData_["Xmp.video.TimeZone"]); - io_->read(buf.pData_, 1); - td2 = find(PictureControlAdjust, (int)buf.pData_[0] & 7 ); - if(td2) - xmpData_["Xmp.video.PictureControlAdjust"] = exvGettext(td2->label_); - else - xmpData_["Xmp.video.PictureControlAdjust"] = (int)buf.pData_[0] & 7 ; + if(xmpData_["Xmp.video.DayLightSavings"].count() >0){ + RevTagDetails revTagDetails[(sizeof(YesNo)/sizeof(YesNo[0]))]; + reverseTagDetails(YesNo,revTagDetails,((sizeof(YesNo)/sizeof(YesNo[0])))); - io_->read(buf.pData_, 1); - td2 = find(NormalSoftHard, (int)buf.pData_[0] & 7 ); - if(td2) - xmpData_["Xmp.video.PictureControlQuickAdjust"] = exvGettext(td2->label_); + rtd2 = find(revTagDetails, xmpData_["Xmp.video.DayLightSavings"].toString() ); + if(rtd2){ + Exiv2::byte rawDayLightSavings = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawDayLightSavings,1); + } + } + if(!bDataWriten) io_->seek(1,BasicIo::cur); + bDataWriten = false; - io_->read(buf.pData_, 1); - td2 = find(NormalSoftHard, (int)buf.pData_[0] & 7 ); - if(td2) - xmpData_["Xmp.video.Sharpness"] = exvGettext(td2->label_); - else - xmpData_["Xmp.video.Sharpness"] = (int)buf.pData_[0] & 7; - - io_->read(buf.pData_, 1); - td2 = find(NormalSoftHard, (int)buf.pData_[0] & 7 ); - if(td2) - xmpData_["Xmp.video.Contrast"] = exvGettext(td2->label_); - else - xmpData_["Xmp.video.Contrast"] = (int)buf.pData_[0] & 7; - - io_->read(buf.pData_, 1); - td2 = find(NormalSoftHard, (int)buf.pData_[0] & 7 ); - if(td2) - xmpData_["Xmp.video.Brightness"] = exvGettext(td2->label_); - else - xmpData_["Xmp.video.Brightness"] = (int)buf.pData_[0] & 7; - - io_->read(buf.pData_, 1); - td2 = find(Saturation, (int)buf.pData_[0] & 7 ); - if(td2) - xmpData_["Xmp.video.Saturation"] = exvGettext(td2->label_); - else - xmpData_["Xmp.video.Saturation"] = (int)buf.pData_[0] & 7; - - io_->read(buf.pData_, 1); - xmpData_["Xmp.video.HueAdjustment"] = (int)buf.pData_[0] & 7; - - io_->read(buf.pData_, 1); - td2 = find(FilterEffect, (int)buf.pData_[0]); - if(td2) - xmpData_["Xmp.video.FilterEffect"] = exvGettext(td2->label_); - else - xmpData_["Xmp.video.FilterEffect"] = (int)buf.pData_[0]; - - io_->read(buf.pData_, 1); - td2 = find(ToningEffect, (int)buf.pData_[0]); - if(td2) - xmpData_["Xmp.video.ToningEffect"] = exvGettext(td2->label_); - else - xmpData_["Xmp.video.ToningEffect"] = (int)buf.pData_[0]; - - io_->read(buf.pData_, 1); xmpData_["Xmp.video.ToningSaturation"] = (int)buf.pData_[0]; + if(xmpData_["Xmp.video.DateDisplayFormat"].count() >0){ + RevTagDetails revTagDetails[(sizeof(DateDisplayFormat)/sizeof(DateDisplayFormat[0]))]; + reverseTagDetails(DateDisplayFormat,revTagDetails,((sizeof(DateDisplayFormat)/sizeof(DateDisplayFormat[0])))); + rtd2 = find(revTagDetails, xmpData_["Xmp.video.DateDisplayFormat"].toString() ); + if(rtd2){ + Exiv2::byte rawDateDisplayFormat = (Exiv2::byte)rtd2->val_; + bDataWriten = writeMultibyte(&rawDateDisplayFormat,1); + } + } io_->seek(local_pos + dataLength, BasicIo::beg); } - - else if(TagID == 0x2000024) { - uint64_t local_pos = io_->tell(); - dataLength = Exiv2::getUShort(buf.pData_, bigEndian); - std::memset(buf.pData_, 0x0, buf.size_); - - io_->read(buf.pData_, 2); xmpData_["Xmp.video.TimeZone"] = Exiv2::getShort(buf.pData_, bigEndian); - io_->read(buf.pData_, 1); - td2 = find(YesNo, (int)buf.pData_[0]); - if(td2) - xmpData_["Xmp.video.DayLightSavings"] = exvGettext(td2->label_); - - io_->read(buf.pData_, 1); - td2 = find(DateDisplayFormat, (int)buf.pData_[0]); - if(td2) - xmpData_["Xmp.video.DateDisplayFormat"] = exvGettext(td2->label_); - - io_->seek(local_pos + dataLength, BasicIo::beg); - } - - else if(dataType == 2 || dataType == 7) { + else if(dataType == 2 || dataType == 7){ dataLength = Exiv2::getUShort(buf.pData_, bigEndian); std::memset(buf.pData_, 0x0, buf.size_); // Sanity check with an "unreasonably" large number - if (dataLength > 200) { + if (dataLength > 200){ #ifndef SUPPRESS_WARNINGS EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be larger than 200." << " Entries considered invalid. Not Processed.\n"; #endif io_->seek(io_->tell() + dataLength, BasicIo::beg); + } else { + if(td && (xmpData_[exvGettext(td->label_)].count() >0)) writeStringData(xmpData_[exvGettext(td->label_)],dataLength); + else io_->seek(dataLength,BasicIo::cur); } - else - io_->read(buf.pData_, dataLength); - - if(td) - xmpData_[exvGettext(td->label_)] = Exiv2::toString(buf.pData_); } - else if(dataType == 4) { + else if(dataType == 4){ // what is 4? would it be better to have an enum with a name for each dataType? dataLength = Exiv2::getUShort(buf.pData_, bigEndian) * 4; - std::memset(buf.pData_, 0x0, buf.size_); - io_->read(buf.pData_, 4); - if(td) - xmpData_[exvGettext(td->label_)] = Exiv2::toString(Exiv2::getULong( buf.pData_, bigEndian)); - - // Sanity check with an "unreasonably" large number - if (dataLength > 200 || dataLength < 4) { -#ifndef SUPPRESS_WARNINGS - EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be of inapropriate size." - << " Entries considered invalid. Not Processed.\n"; -#endif - io_->seek(io_->tell() + dataLength - 4, BasicIo::beg); - } - else - io_->read(buf.pData_, dataLength - 4); + if(td && (xmpData_[exvGettext(td->label_)].count() >0) && (dataLength < 200)) writeLongData(xmpData_[exvGettext(td->label_)],4,dataLength-4); + else io_->seek(dataLength,BasicIo::cur); } - else if(dataType == 3) { + else if(dataType == 3){ dataLength = Exiv2::getUShort(buf.pData_, bigEndian) * 2; std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 2); - if(td) - xmpData_[exvGettext(td->label_)] = Exiv2::toString(Exiv2::getUShort( buf.pData_, bigEndian)); - - // Sanity check with an "unreasonably" large number - if (dataLength > 200 || dataLength < 2) { -#ifndef SUPPRESS_WARNINGS - EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be of inapropriate size." - << " Entries considered invalid. Not Processed.\n"; -#endif - io_->seek(io_->tell() + dataLength - 2, BasicIo::beg); - } - else - io_->read(buf.pData_, dataLength - 2); + if(td &&(xmpData_[exvGettext(td->label_)].count() >0) && (dataLength < 200)) writeShortData(xmpData_[exvGettext(td->label_)],2,dataLength-2); + else io_->seek(dataLength,BasicIo::cur); } - else if(dataType == 5) { + else if(dataType == 5){ dataLength = Exiv2::getUShort(buf.pData_, bigEndian) * 8; std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 4); io_->read(buf2.pData_, 4); - if(td) - xmpData_[exvGettext(td->label_)] = Exiv2::toString((double)Exiv2::getULong( buf.pData_, bigEndian) / (double)Exiv2::getULong( buf2.pData_, bigEndian)); - - // Sanity check with an "unreasonably" large number - if (dataLength > 200 || dataLength < 8) { -#ifndef SUPPRESS_WARNINGS - EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be of inapropriate size." - << " Entries considered invalid. Not Processed.\n"; -#endif - io_->seek(io_->tell() + dataLength - 8, BasicIo::beg); + if(td && (xmpData_[exvGettext(td->label_)].count() >0) &&(dataLength < 200)){ + io_->seek(-8,BasicIo::cur); + const int32_t tagData = (int32_t)((double)xmpData_[exvGettext(td->label_)].toLong()* + (double)Exiv2::getULong( buf2.pData_, bigEndian)); + io_->write((Exiv2::byte*)&tagData,4); + io_->seek((dataLength-4),BasicIo::cur); } - else - io_->read(buf.pData_, dataLength - 8); + else io_->seek(dataLength,BasicIo::cur); } - else if(dataType == 8) { + else if(dataType == 8){ dataLength = Exiv2::getUShort(buf.pData_, bigEndian) * 2; std::memset(buf.pData_, 0x0, buf.size_); - io_->read(buf.pData_, 2); - io_->read(buf2.pData_, 2); - if(td) - xmpData_[exvGettext(td->label_)] = Exiv2::toString(Exiv2::getUShort( buf.pData_, bigEndian) ) + " " + Exiv2::toString(Exiv2::getUShort( buf2.pData_, bigEndian)); - - // Sanity check with an "unreasonably" large number - if (dataLength > 200 || dataLength < 4) { -#ifndef SUPPRESS_WARNINGS - EXV_ERROR << "Xmp.video Nikon Tags, dataLength was found to be of inapropriate size." - << " Entries considered invalid. Not Processed.\n"; -#endif - io_->seek(io_->tell() + dataLength - 4, BasicIo::beg); + if(td && (xmpData_[exvGettext(td->label_)].count() >0) &&(dataLength < 200)){ + vector dataEight = getNumberFromString(xmpData_[exvGettext(td->label_)].toString(),' '); + io_->write((Exiv2::byte*)&dataEight[0],2); + io_->write((Exiv2::byte*)&dataEight[1],2); + io_->seek(dataLength - 4,BasicIo::cur); } - else - io_->read(buf.pData_, dataLength - 4); + else io_->seek(dataLength - 4,BasicIo::cur); } } - io_->seek(cur_pos + size_external, BasicIo::beg); - } // QuickTimeVideo::NikonTagsDecoder + } +} - void QuickTimeVideo::setMediaStream() - { - uint64_t current_position = io_->tell(); - DataBuf buf(4+1); +void QuickTimeVideo::setMediaStream(uint32_t /* iDummySize*/) +{ + uint64_t current_position = io_->tell(); + DataBuf buf(4+1); - while(!io_->eof()) { + while( !io_->eof() ) { + io_->read(buf.pData_, 4); + if (UtilsVideo::compareTagValue(buf, "hdlr")) { + io_->seek(8,BasicIo::cur); io_->read(buf.pData_, 4); - if (equalsQTimeTag(buf, "hdlr")) { - io_->read(buf.pData_, 4); - io_->read(buf.pData_, 4); - io_->read(buf.pData_, 4); - if (equalsQTimeTag(buf, "vide")) - currentStream_ = Video; - else if(equalsQTimeTag(buf, "soun")) - currentStream_ = Audio; - else if (equalsQTimeTag(buf, "hint")) - currentStream_ = Hint; - else - currentStream_ = GenMediaHeader; - break; - } + if (UtilsVideo::compareTagValue(buf, "vide")) d->currentStream_ = Video; + else if (UtilsVideo::compareTagValue(buf, "soun")) d->currentStream_ = Audio; + else if (UtilsVideo::compareTagValue(buf, "hint")) d->currentStream_ = Hint; + else d->currentStream_ = GenMediaHeader; + break; } + } + io_->seek(current_position, BasicIo::beg); +} - io_->seek(current_position, BasicIo::beg); - } // QuickTimeVideo::setMediaStream +void QuickTimeVideo::timeToSampleDecoder(uint32_t/* iDummySize*/) +{ + DataBuf buf(4+1); + io_->read(buf.pData_, 4); + io_->read(buf.pData_, 4); + uint64_t totalframes = 0; + uint64_t timeOfFrames = 0; - void QuickTimeVideo::timeToSampleDecoder() - { - DataBuf buf(4+1); + uint64_t noOfEntries = returnUnsignedBufValue(buf); + for(uint32_t i=1; i <= noOfEntries; i++){ io_->read(buf.pData_, 4); + uint64_t temp = returnBufValue(buf); + totalframes += temp; io_->read(buf.pData_, 4); - uint64_t noOfEntries, totalframes = 0, timeOfFrames = 0; - noOfEntries = returnUnsignedBufValue(buf); - uint64_t temp; + timeOfFrames += temp * returnBufValue(buf); + } - for(unsigned long i = 1; i <= noOfEntries; i++) { - io_->read(buf.pData_, 4); - temp = returnBufValue(buf); - totalframes += temp; - io_->read(buf.pData_, 4); - timeOfFrames += temp * returnBufValue(buf); + if(!d->m_modifyMetadata) { + if (d->currentStream_ == Video) { + xmpData_["Xmp.video.FrameRate"] = (double)totalframes * (double)d->timeScale_ / (double)timeOfFrames; + } else { + if(xmpData_["Xmp.video.FrameRate"].count() >0) { /* TODO:implement write */ } + // Really? We're not modifying!! } - if (currentStream_ == Video) - xmpData_["Xmp.video.FrameRate"] = (double)totalframes * (double)timeScale_ / (double)timeOfFrames; - } // QuickTimeVideo::timeToSampleDecoder + } +} - void QuickTimeVideo::sampleDesc(unsigned long size) - { - DataBuf buf(100); - uint64_t cur_pos = io_->tell(); - io_->read(buf.pData_, 4); - io_->read(buf.pData_, 4); - uint64_t noOfEntries; - noOfEntries = returnUnsignedBufValue(buf); +void QuickTimeVideo::sampleDesc(uint32_t size) +{ + DataBuf buf(100); + uint64_t cur_pos = io_->tell(); + io_->read(buf.pData_, 4); + io_->read(buf.pData_, 4); + uint32_t noOfEntries = returnUnsignedBufValue(buf); + for(uint32_t i = 1; i <= noOfEntries; i++){ + if (d->currentStream_ == Video) imageDescDecoder(); + else if (d->currentStream_ == Audio) audioDescDecoder(); + } + io_->seek(cur_pos + size, BasicIo::beg); +} - for(unsigned long i = 1; i <= noOfEntries; i++) { - if (currentStream_ == Video) - imageDescDecoder(); - else if (currentStream_ == Audio) - audioDescDecoder(); - } - io_->seek(cur_pos + size, BasicIo::beg); - } // QuickTimeVideo::sampleDesc +void QuickTimeVideo::audioDescDecoder() +{ + DataBuf buf(40); + io_->read(buf.pData_, 4); + uint64_t size = 82; - void QuickTimeVideo::audioDescDecoder() - { - DataBuf buf(40); - std::memset(buf.pData_, 0x0, buf.size_); - buf.pData_[4] = '\0'; - io_->read(buf.pData_, 4); - uint64_t size = 82; + const TagVocabulary* td; - const TagVocabulary* td; - - for (int i = 0; size/4 != 0 ; size -= 4, i++) { + if(!d->m_modifyMetadata){ + for (int32_t i = 0; size/4 != 0 ; size -= 4, i++){ io_->read(buf.pData_, 4); - switch(i) { + switch(i){ case AudioFormat: td = find(qTimeFileType, Exiv2::toString( buf.pData_)); - if(td) - xmpData_["Xmp.audio.Compressor"] = exvGettext(td->label_); - else - xmpData_["Xmp.audio.Compressor"] = Exiv2::toString( buf.pData_); + if(td) xmpData_["Xmp.audio.Compressor"] = exvGettext(td->label_); + else xmpData_["Xmp.audio.Compressor"] = Exiv2::toString( buf.pData_); break; + case AudioVendorID: td = find(vendorIDTags, Exiv2::toString( buf.pData_)); - if(td) - xmpData_["Xmp.audio.VendorID"] = exvGettext(td->label_); + if(td) xmpData_["Xmp.audio.VendorID"] = exvGettext(td->label_); break; + case AudioChannels: - xmpData_["Xmp.audio.ChannelType"] = returnBufValue(buf, 2); + xmpData_["Xmp.audio.ChannelType"] = returnBufValue(buf, 2); xmpData_["Xmp.audio.BitsPerSample"] = (buf.pData_[2] * 256 + buf.pData_[3]); break; + case AudioSampleRate: xmpData_["Xmp.audio.SampleRate"] = returnBufValue(buf, 2) + ((buf.pData_[2] * 256 + buf.pData_[3]) * 0.01); break; - default: - break; + + default: break; } } - io_->read(buf.pData_, static_cast(size % 4)); //cause size is so small, this cast should be right. - } // QuickTimeVideo::audioDescDecoder + io_->read(buf.pData_, static_cast(size % 4)); //cause size is so small, this cast should be right. + } else { + TagVocabulary revTagVocabulary[(sizeof(qTimeFileType)/sizeof(qTimeFileType[0]))]; + reverseTagVocabulary(qTimeFileType,revTagVocabulary,((sizeof(qTimeFileType)/sizeof(qTimeFileType[0])))); - void QuickTimeVideo::imageDescDecoder() - { - DataBuf buf(40); - std::memset(buf.pData_, 0x0, buf.size_); - buf.pData_[4] = '\0'; - io_->read(buf.pData_, 4); - uint64_t size = 82; + TagVocabulary revVendorIDTags[(sizeof(vendorIDTags)/sizeof(vendorIDTags[0]))]; + reverseTagVocabulary(vendorIDTags,revVendorIDTags,((sizeof(vendorIDTags)/sizeof(vendorIDTags[0])))); - const TagVocabulary* td; + for (int32_t i = 0; size/4 != 0 ; size -= 4, i++){ + bool bDataWriten = false; + switch(i){ + case AudioFormat: + if(xmpData_["Xmp.audio.Compressor"].count() > 0){ + Exiv2::byte rawCompressor[4]; + td = find(revTagVocabulary,xmpData_["Xmp.audio.Compressor"].toString()); + if(td){ + const char* compressor = td->label_; + for(int32_t j=0; j<4; j++) rawCompressor[j] = compressor[j]; + bDataWriten = writeMultibyte(rawCompressor, 4); + } + } + break; - for (int i = 0; size/4 != 0 ; size -= 4, i++) { + case AudioVendorID: + if(xmpData_["Xmp.audio.VendorID"].count() >0){ + Exiv2::byte rawVendorID[4]; + td = find(revVendorIDTags,xmpData_["Xmp.audio.VendorID"].toString()); + if(td){ + const char* vendorID = td->label_; + for(int32_t j=0; j<4; j++) rawVendorID[j] = vendorID[j]; + bDataWriten = writeMultibyte(rawVendorID, 4); + } + } + break; + + case AudioChannels: + if(xmpData_["Xmp.audio.ChannelType"].count() >0){ + DataBuf rawBuf(2); + rawBuf = returnBuf((int64_t)xmpData_["Xmp.audio.ChannelType"].toLong(),2); + bDataWriten = writeMultibyte(rawBuf.pData_, 2); + } + if(!bDataWriten) io_->seek(2, BasicIo::cur); + bDataWriten = false; + + if(xmpData_["Xmp.audio.BitsPerSample"].count() >0){ + DataBuf rawBuf(2); + rawBuf = returnBuf((int64_t)xmpData_["Xmp.audio.BitsPerSample"].toLong(),2); + bDataWriten = writeMultibyte(rawBuf.pData_,2); + } + if(!bDataWriten) io_->seek(2, BasicIo::cur); + bDataWriten = true; + break; + + case AudioSampleRate: + if(xmpData_["Xmp.audio.SampleRate"].count() >0){ + DataBuf rawSampleRate(5); + rawSampleRate.pData_[4] = '\0'; + const int64_t sampleRate = (int64_t)xmpData_["Xmp.audio.SampleRate"].toLong(); + rawSampleRate = returnBuf(sampleRate,4); + + bDataWriten = writeMultibyte(rawSampleRate.pData_+2,2); + bDataWriten = writeMultibyte(rawSampleRate.pData_,2); + } + break; + + default: + io_->seek(4,BasicIo::cur); + bDataWriten = true; + break; + } + if(!bDataWriten) io_->seek(4, BasicIo::cur); + } + io_->seek(static_cast(size % 4),BasicIo::cur); + } +} + +void QuickTimeVideo::imageDescDecoder() +{ + DataBuf buf(40); + io_->read(buf.pData_, 4); + uint64_t size = 82; + + const TagVocabulary* td; + + if(!d->m_modifyMetadata){ + for (int32_t i = 0; size/4 != 0 ; size -= 4, i++){ io_->read(buf.pData_, 4); - switch(i) { + switch(i){ case codec: td = find(qTimeFileType, Exiv2::toString( buf.pData_)); - if(td) - xmpData_["Xmp.video.Codec"] = exvGettext(td->label_); - else - xmpData_["Xmp.video.Codec"] = Exiv2::toString( buf.pData_); + if(td) xmpData_["Xmp.video.Codec"] = exvGettext(td->label_); + else xmpData_["Xmp.video.Codec"] = Exiv2::toString( buf.pData_); break; - case VendorID: - td = find(vendorIDTags, Exiv2::toString( buf.pData_)); - if(td) - xmpData_["Xmp.video.VendorID"] = exvGettext(td->label_); + + case VendorID: td = find(vendorIDTags, Exiv2::toString( buf.pData_)); + if(td) xmpData_["Xmp.video.VendorID"] = exvGettext(td->label_); break; + case SourceImageWidth_Height: xmpData_["Xmp.video.SourceImageWidth"] = returnBufValue(buf, 2); xmpData_["Xmp.video.SourceImageHeight"] = (buf.pData_[2] * 256 + buf.pData_[3]); break; + case XResolution: xmpData_["Xmp.video.XResolution"] = returnBufValue(buf, 2) + ((buf.pData_[2] * 256 + buf.pData_[3]) * 0.01); break; + case YResolution: xmpData_["Xmp.video.YResolution"] = returnBufValue(buf, 2) + ((buf.pData_[2] * 256 + buf.pData_[3]) * 0.01); - io_->read(buf.pData_, 3); size -= 3; + io_->read(buf.pData_, 3); + size -= 3; break; + case CompressorName: io_->read(buf.pData_, 32); size -= 32; xmpData_["Xmp.video.Compressor"] = Exiv2::toString( buf.pData_); break; - default: - break; } } - io_->read(buf.pData_, static_cast(size % 4)); + io_->read(buf.pData_, static_cast(size % 4)); xmpData_["Xmp.video.BitDepth"] = returnBufValue(buf, 1); - } // QuickTimeVideo::imageDescDecoder + } else { + TagVocabulary revTagVocabulary[(sizeof(qTimeFileType)/sizeof(qTimeFileType[0]))]; + reverseTagVocabulary(qTimeFileType,revTagVocabulary,((sizeof(qTimeFileType)/sizeof(qTimeFileType[0])))); - void QuickTimeVideo::multipleEntriesDecoder() - { - DataBuf buf(4+1); - io_->read(buf.pData_, 4); - io_->read(buf.pData_, 4); - uint64_t noOfEntries; + TagVocabulary revVendorIDTags[(sizeof(vendorIDTags)/sizeof(vendorIDTags[0]))]; + reverseTagVocabulary(vendorIDTags,revVendorIDTags,((sizeof(vendorIDTags)/sizeof(vendorIDTags[0])))); - noOfEntries = returnUnsignedBufValue(buf); + for (int32_t i = 0; size/4 != 0 ; size -= 4, i++){ + bool bDataWritten = false; + switch(i){ + case codec: + if(xmpData_["Xmp.video.Codec"].count() >0){ + std::string codecName = xmpData_["Xmp.video.Codec"].toString(); + td = find(revTagVocabulary, codecName); + Exiv2::byte rawCodec[4]; + if(td){ + const char* codecNameTag = td->label_; + for(int32_t j=0; j<4 ;j++) rawCodec[j] = (Exiv2::byte)codecNameTag[j]; + } + else for(int32_t j=0; j<4 ;j++) rawCodec[j] = (Exiv2::byte)codecName[j]; + bDataWritten = writeMultibyte(rawCodec, 4); + } + break; - for(unsigned long i = 1; i <= noOfEntries; i++) - decodeBlock(); - } // QuickTimeVideo::multipleEntriesDecoder + case VendorID: + if(xmpData_["Xmp.video.VendorID"].count() >0){ + td = find(revVendorIDTags, xmpData_["Xmp.video.VendorID"].toString()); + if(td){ + Exiv2::byte rawVendorID[4]; + const char* vendorID = td->label_; + for(int32_t j=0; j<4 ;j++) rawVendorID[j] = vendorID[j]; + bDataWritten = writeMultibyte(rawVendorID,4); + } + } + break; - void QuickTimeVideo::videoHeaderDecoder(unsigned long size) { - DataBuf buf(3); - std::memset(buf.pData_, 0x0, buf.size_); - buf.pData_[2] = '\0'; - currentStream_ = Video; + case SourceImageWidth_Height: + if(xmpData_["Xmp.video.SourceImageWidth"].count() >0){ + DataBuf imageWidth = returnBuf((int64_t)xmpData_["Xmp.video.SourceImageWidth"].toLong(),2); + bDataWritten = writeMultibyte(imageWidth.pData_,2); + } + if(!bDataWritten) io_->seek(2,BasicIo::cur); + bDataWritten = false; - const TagDetails* td; + if(xmpData_["Xmp.video.SourceImageHeight"].count() >0){ + DataBuf imageHeight = returnBuf(((int64_t)(xmpData_["Xmp.video.SourceImageHeight"].toLong() - + xmpData_["Xmp.video.SourceImageHeight"].toLong()/65536)*65536)); + bDataWritten = writeMultibyte(imageHeight.pData_,2); + } + if(!bDataWritten) io_->seek(2,BasicIo::cur); + bDataWritten = true; + break; - for (int i = 0; size/2 != 0 ; size -= 2, i++) { + case XResolution: + //This field should not be edited + break; + + case YResolution: + io_->seek(7,BasicIo::cur); + size -= 3; + bDataWritten = true; + break; + + case CompressorName: + if(xmpData_["Xmp.video.Compressor"].count() >0){ + Exiv2::byte rawCompressor[32] = {}; + const std::string compressor = xmpData_["Xmp.video.Compressor"].toString(); + for(int32_t j=0;jseek(4,BasicIo::cur); + bDataWritten = writeMultibyte(rawCompressor,32); + } else io_->seek(36,BasicIo::cur); + size -= 32; + bDataWritten = true; + break; + } + if(!bDataWritten) io_->seek(4,BasicIo::cur); + } + + if(xmpData_["Xmp.video.BitDepth"].count() > 0) + { + DataBuf rawBitDepth(1); + rawBitDepth = returnBuf((int64_t)xmpData_["Xmp.video.BitDepth"].toLong(),1); + io_->write(rawBitDepth.pData_,1); + } + io_->seek(static_cast(size % 4),BasicIo::cur); + } +} + +void QuickTimeVideo::multipleEntriesDecoder(uint32_t /*iDummySize*/) +{ + DataBuf buf(5); + io_->read(buf.pData_, 4); + io_->read(buf.pData_, 4); + + uint64_t noOfEntries = returnUnsignedBufValue(buf); + for(uint32_t i = 1; i <= noOfEntries; i++) decodeBlock(); +} + +void QuickTimeVideo::videoHeaderDecoder(uint32_t size) +{ + DataBuf buf(3); + d->currentStream_ = Video; + + const RevTagDetails* rtd; + const TagDetails* td; + + if(!d->m_modifyMetadata){ + for (int32_t i = 0; size/2 != 0 ; size -= 2, i++){ io_->read(buf.pData_, 2); - switch(i) { + switch(i){ case GraphicsMode: td = find(graphicsModetags, returnBufValue(buf,2)); - if(td) - xmpData_["Xmp.video.GraphicsMode"] = exvGettext(td->label_); + if(td) xmpData_["Xmp.video.GraphicsMode"] = exvGettext(td->label_); break; + case OpColor: xmpData_["Xmp.video.OpColor"] = returnBufValue(buf,2); break; - default: - break; } } io_->read(buf.pData_, size % 2); - } // QuickTimeVideo::videoHeaderDecoder + } else { + RevTagDetails revTagDetails[(sizeof(graphicsModetags)/sizeof(graphicsModetags[0]))]; + reverseTagDetails(graphicsModetags,revTagDetails,((sizeof(graphicsModetags)/sizeof(graphicsModetags[0])))); - void QuickTimeVideo::handlerDecoder(unsigned long size) - { - uint64_t cur_pos = io_->tell(); - DataBuf buf(100); - std::memset(buf.pData_, 0x0, buf.size_); - buf.pData_[4] = '\0'; + for (int32_t i = 0; size/2 != 0 ; size -= 2, i++){ + bool bDataWritten = false; + switch(i){ + case GraphicsMode: + if(xmpData_["Xmp.video.GraphicsMode"].count() >0){ + DataBuf rawGraphicsMode(2); + rtd = find(revTagDetails,xmpData_["Xmp.video.GraphicsMode"].toString()); + if(rtd){ + rawGraphicsMode = returnBuf((int64_t)rtd->val_,2); + bDataWritten = writeMultibyte(rawGraphicsMode.pData_,2); + } + } + break; - const TagVocabulary* tv; + case OpColor: + if(xmpData_["Xmp.video.OpColor"].count() >0){ + DataBuf rawOpColor((uint32_t)3); + rawOpColor.pData_[2] = '\0'; + const int64_t opColor = xmpData_["Xmp.video.OpColor"].toLong(); + rawOpColor = returnBuf(opColor,2); + bDataWritten = writeMultibyte(rawOpColor.pData_,2); + } + break; + } + if(!bDataWritten) io_->seek(2,BasicIo::cur); + } + io_->seek(size % 2,BasicIo::cur); + } +} - for (int i = 0; i < 5 ; i++) { +void QuickTimeVideo::handlerDecoder(uint32_t size) +{ + uint64_t cur_pos = io_->tell(); + DataBuf buf(100); + const TagVocabulary* tv; + + if(!d->m_modifyMetadata){ + for (int32_t i = 0; i < 5 ; i++){ io_->read(buf.pData_, 4); - switch(i) { + switch(i){ case HandlerClass: tv = find(handlerClassTags, Exiv2::toString( buf.pData_)); - if(tv) { - if (currentStream_ == Video) - xmpData_["Xmp.video.HandlerClass"] = exvGettext(tv->label_); - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.HandlerClass"] = exvGettext(tv->label_); + if(tv){ + if (d->currentStream_ == Video) xmpData_["Xmp.video.HandlerClass"] = exvGettext(tv->label_); + else if (d->currentStream_ == Audio) xmpData_["Xmp.audio.HandlerClass"] = exvGettext(tv->label_); } break; + case HandlerType: tv = find(handlerTypeTags, Exiv2::toString( buf.pData_)); - if(tv) { - if (currentStream_ == Video) - xmpData_["Xmp.video.HandlerType"] = exvGettext(tv->label_); - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.HandlerType"] = exvGettext(tv->label_); + if(tv){ + if (d->currentStream_ == Video) xmpData_["Xmp.video.HandlerType"] = exvGettext(tv->label_); + else if (d->currentStream_ == Audio) xmpData_["Xmp.audio.HandlerType"] = exvGettext(tv->label_); } break; + case HandlerVendorID: tv = find(vendorIDTags, Exiv2::toString( buf.pData_)); - if(tv) { - if (currentStream_ == Video) - xmpData_["Xmp.video.HandlerVendorID"] = exvGettext(tv->label_); - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.HandlerVendorID"] = exvGettext(tv->label_); + if(tv){ + if (d->currentStream_ == Video) xmpData_["Xmp.video.HandlerVendorID"] = exvGettext(tv->label_); + else if (d->currentStream_ == Audio) xmpData_["Xmp.audio.HandlerVendorID"] = exvGettext(tv->label_); } break; } } io_->seek(cur_pos + size, BasicIo::beg); - } // QuickTimeVideo::handlerDecoder + } else { + for (int32_t i = 0; i < 5 ; i++){ + bool bDataWritten = false; + switch(i){ + case HandlerClass : bDataWritten = writeAudVidData(0); break; + case HandlerType : bDataWritten = writeAudVidData(1); break; + case HandlerVendorID: bDataWritten = writeAudVidData(2); break; + } + if(!bDataWritten) io_->seek(4, BasicIo::cur); + } + io_->seek(cur_pos + size, BasicIo::beg); + } +} - void QuickTimeVideo::fileTypeDecoder(unsigned long size) { - DataBuf buf(5); - std::memset(buf.pData_, 0x0, buf.size_); - buf.pData_[4] = '\0'; - Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpSeq); - const TagVocabulary* td; +bool QuickTimeVideo::writeAudVidData(int64_t iTagType) +{ + bool bReturnVal = false; + const TagVocabulary* tv; - for (int i = 0; size/4 != 0; size -=4, i++) { + TagVocabulary revTagVocabulary[(sizeof(handlerClassTags)/sizeof(handlerClassTags[0]))]; + reverseTagVocabulary(handlerClassTags,revTagVocabulary,((sizeof(handlerClassTags)/sizeof(handlerClassTags[0])))); + + TagVocabulary revHandlerType[(sizeof(handlerTypeTags)/sizeof(handlerTypeTags[0]))]; + reverseTagVocabulary(handlerTypeTags,revHandlerType,((sizeof(handlerTypeTags)/sizeof(handlerTypeTags[0])))); + + TagVocabulary revVendorIDTags[(sizeof(vendorIDTags)/sizeof(vendorIDTags[0]))]; + reverseTagVocabulary(vendorIDTags,revVendorIDTags,((sizeof(vendorIDTags)/sizeof(vendorIDTags[0])))); + + if(d->currentStream_ == Video){ + switch (iTagType) { + case 0: tv = find(revTagVocabulary, xmpData_["Xmp.video.HandlerClass"].toString()) ; break; + case 1: tv = find(revHandlerType, xmpData_["Xmp.video.HandlerType"].toString()) ; break; + case 2: tv = find(revVendorIDTags, xmpData_["Xmp.video.HandlerVendorID"].toString()) ; break; + } + } + if(d->currentStream_ == Audio){ + switch (iTagType) { + case 0: tv = find(revTagVocabulary, xmpData_["Xmp.audio.HandlerClass"].toString()) ; break; + case 1: tv = find(revHandlerType, xmpData_["Xmp.audio.HandlerType"].toString()) ; break; + case 2: tv = find(revVendorIDTags, xmpData_["Xmp.audio.HandlerVendorID"].toString()) ; break; + } + } + if(tv){ + Exiv2::byte sRawXmpTagVal[4]; + const std::string sXmpTagVal = tv->label_; + for(int32_t j=0; j<4; j++) sRawXmpTagVal[j] = sXmpTagVal[j]; + bReturnVal = writeMultibyte(sRawXmpTagVal,4); + } + return bReturnVal; +} + +void QuickTimeVideo::fileTypeDecoder(uint32_t size) +{ + DataBuf buf(5); + Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpSeq); + const TagVocabulary* td; + + if(!d->m_modifyMetadata){ + for (int32_t i = 0; size/4 != 0; size -=4, i++){ io_->read(buf.pData_, 4); td = find(qTimeFileType, Exiv2::toString( buf.pData_)); - - switch(i) { - case 0: - if(td) - xmpData_["Xmp.video.MajorBrand"] = exvGettext(td->label_); - break; - case 1: - xmpData_["Xmp.video.MinorVersion"] = returnBufValue(buf); - break; - default: - if(td) - v->read(exvGettext(td->label_)); - else - v->read(Exiv2::toString(buf.pData_)); + switch(i){ + case 0: if(td) xmpData_["Xmp.video.MajorBrand"] = exvGettext(td->label_); break; + case 1: xmpData_["Xmp.video.MinorVersion"] = returnBufValue(buf); break; + default: if(td) v->read(exvGettext(td->label_)); + else v->read(Exiv2::toString(buf.pData_)); break; } + xmpData_.add(Exiv2::XmpKey("Xmp.video.CompatibleBrands"), v.get()); + io_->read(buf.pData_, size%4); } - xmpData_.add(Exiv2::XmpKey("Xmp.video.CompatibleBrands"), v.get()); - io_->read(buf.pData_, size%4); - } // QuickTimeVideo::fileTypeDecoder - - void QuickTimeVideo::mediaHeaderDecoder(unsigned long size) { - DataBuf buf(5); - std::memset(buf.pData_, 0x0, buf.size_); - buf.pData_[4] = '\0'; - int64_t time_scale = 1; - - for (int i = 0; size/4 != 0 ; size -=4, i++) { - io_->read(buf.pData_, 4); - - switch(i) { - case MediaHeaderVersion: - if(currentStream_ == Video) - xmpData_["Xmp.video.MediaHeaderVersion"] = returnBufValue(buf,1); - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.MediaHeaderVersion"] = returnBufValue(buf,1); + } else { + TagVocabulary revTagVocabulary[(sizeof(qTimeFileType)/sizeof(qTimeFileType[0]))]; + reverseTagVocabulary(qTimeFileType,revTagVocabulary,((sizeof(qTimeFileType)/sizeof(qTimeFileType[0])))); + DataBuf buf; + for (int32_t i = 0; size/4 != 0; size -=4, i++){ + bool bDataWritten = false; + switch(i){ + case 0: + if(xmpData_["Xmp.video.MajorBrand"].count() > 0){ + Exiv2::byte rawMajorBrand[4]; + td = find(revTagVocabulary, xmpData_["Xmp.video.MajorBrand"].toString()); + const char* majorBrandVoc = td->label_; + for(int32_t j=0; j<4 ;j++)rawMajorBrand[j] = majorBrandVoc[i]; + bDataWritten = writeMultibyte(rawMajorBrand,4); + } break; - case MediaCreateDate: - //A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. - if(currentStream_ == Video) - xmpData_["Xmp.video.MediaCreateDate"] = returnUnsignedBufValue(buf); - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.MediaCreateDate"] = returnUnsignedBufValue(buf); + + case 1: + if(xmpData_["Xmp.video.MinorVersion"].count() >0){ + buf = returnBuf((int64_t)xmpData_["Xmp.video.MinorVersion"].toLong()); + bDataWritten = writeMultibyte(buf.pData_,4); + } break; - case MediaModifyDate: - //A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. - if(currentStream_ == Video) - xmpData_["Xmp.video.MediaModifyDate"] = returnUnsignedBufValue(buf); - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.MediaModifyDate"] = returnUnsignedBufValue(buf); + + default: + if(xmpData_["Xmp.video.CompatibleBrands"].count() >0){ + Exiv2::byte rawCompatibleBrand[4]; + td = find(revTagVocabulary, xmpData_["Xmp.video.CompatibleBrands"].toString()); + if(td){ + const char* compatibleBrandVoc = td->label_; + for(int32_t j=0; j<4 ;j++) rawCompatibleBrand[i] = compatibleBrandVoc[i]; + } else { + const std::string compatibleBrand = xmpData_["Xmp.video.CompatibleBrands"].toString(); + for(int32_t j=0; j<4; j++) rawCompatibleBrand[i] = compatibleBrand[i]; + } + bDataWritten = writeMultibyte(rawCompatibleBrand,4); + } break; - case MediaTimeScale: - if(currentStream_ == Video) - xmpData_["Xmp.video.MediaTimeScale"] = returnBufValue(buf); - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.MediaTimeScale"] = returnBufValue(buf); + } + if(!bDataWritten) io_->seek(4, BasicIo::cur); + io_->seek(size%4,BasicIo::cur); + } + } +} + +void QuickTimeVideo::mediaHeaderDecoder(uint32_t size) +{ + DataBuf buf(5); + int64_t time_scale = 1; + const TagDetails* td; + const RevTagDetails* rtd; + + if(!d->m_modifyMetadata){ + for (int32_t i = 0; size/4 != 0 ; size -=4, i++){ + + switch(i){ + case MediaHeaderVersion: readAudVidData("MediaHeaderVersion", 1, 1, 0); break; + case MediaCreateDate: //A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. + readAudVidData("MediaCreateDate", 4, 1, 1); break; + case MediaModifyDate: //A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. + readAudVidData("MediaModifyDate", 4, 1, 1); break; + case MediaTimeScale: io_->read(buf.pData_, 4) ;if(d->currentStream_ == Video) xmpData_["Xmp.video.MediaTimeScale"] = returnBufValue(buf); + else if (d->currentStream_ == Audio) xmpData_["Xmp.audio.MediaTimeScale"] = returnBufValue(buf); time_scale = returnBufValue(buf); break; - case MediaDuration: - if(currentStream_ == Video) - xmpData_["Xmp.video.MediaDuration"] = returnBufValue(buf)/time_scale; - else if (currentStream_ == Audio) - xmpData_["Xmp.audio.MediaDuration"] = returnBufValue(buf)/time_scale; + + case MediaDuration: io_->read(buf.pData_, 4); + if(d->currentStream_ == Video) xmpData_["Xmp.video.MediaDuration"] = returnBufValue(buf)/time_scale; + else if (d->currentStream_ == Audio) xmpData_["Xmp.audio.MediaDuration"] = returnBufValue(buf)/time_scale; break; - case MediaLanguageCode: - if(currentStream_ == Video) + case MediaLanguageCode: io_->read(buf.pData_, 4); + if(d->currentStream_ == Video){ + DataBuf tmpBuf((uint32_t)5); + tmpBuf.pData_[1] = buf.pData_[2]; + tmpBuf.pData_[0] = buf.pData_[3]; + xmpData_["Xmp.video.Quality"] = returnUnsignedBufValue(tmpBuf,2); xmpData_["Xmp.video.MediaLangCode"] = returnUnsignedBufValue(buf,2); - else if (currentStream_ == Audio) + td = find(mediaLanguageCode,returnUnsignedBufValue(buf,2)); + if(td) xmpData_["Xmp.video.MediaLanguage"] = Exiv2::StringValue(td->label_); + } else if (d->currentStream_ == Audio){ + DataBuf tmpBuf((uint32_t)5); + tmpBuf.pData_[1] = buf.pData_[2]; + tmpBuf.pData_[0] = buf.pData_[3]; + xmpData_["Xmp.audio.Quality"] = returnUnsignedBufValue(tmpBuf,2); xmpData_["Xmp.audio.MediaLangCode"] = returnUnsignedBufValue(buf,2); + td = find(mediaLanguageCode,returnUnsignedBufValue(buf,2)); + if(td) xmpData_["Xmp.audio.MediaLanguage"] = Exiv2::StringValue(td->label_); + } break; - - default: - break; + default: io_->seek(4, BasicIo::cur); break; } } io_->read(buf.pData_, size%4); - } // QuickTimeVideo::mediaHeaderDecoder + } else { + RevTagDetails revTagDetails[(sizeof(mediaLanguageCode)/sizeof(mediaLanguageCode[0]))]; + reverseTagDetails(mediaLanguageCode,revTagDetails,((sizeof(mediaLanguageCode)/sizeof(mediaLanguageCode[0])))); - void QuickTimeVideo::trackHeaderDecoder(unsigned long size) { - DataBuf buf(5); - std::memset(buf.pData_, 0x0, buf.size_); - buf.pData_[4] = '\0'; - int64_t temp = 0; + for (int32_t i = 0; size/4 != 0 ; size -=4, i++){ + bool bDataWritten = false; + switch(i){ + case MediaHeaderVersion: + bDataWritten = writeAudVidData("MediaHeaderVersion", 1, 1, 3, 0); + break; + case MediaCreateDate: bDataWritten = writeAudVidData("MediaCreateDate", 1, 4, 0, 1); break; + case MediaModifyDate: bDataWritten = writeAudVidData("MediaModifyDate", 1, 4, 0, 1); break; + case MediaTimeScale: bDataWritten = writeAudVidData("MediaTimeScale", 1, 4, -4, 0); break; + case MediaDuration: + io_->read(buf.pData_,4); + time_scale = returnBufValue(buf); + bDataWritten = writeAudVidData("MediaDuration", time_scale, 4, 0, 0); break; + case MediaLanguageCode: + if(d->currentStream_ == Video){ + if(xmpData_["Xmp.video.MediaLanguage"].count() > 0){ + rtd = find(revTagDetails,xmpData_["Xmp.video.MediaLanguage"].toString()); + if(rtd){ + buf = returnBuf(rtd->val_,2); + bDataWritten = writeMultibyte(buf.pData_,2); + } + } + if(!bDataWritten) io_->seek(2,BasicIo::cur); + bDataWritten = false; + if(xmpData_["Xmp.video.Quality"].count() >0){ + buf = returnBuf((uint64_t)xmpData_["Xmp.video.Quality"].toLong(),2); + bDataWritten = writeMultibyte(&buf.pData_[1],1); + bDataWritten = writeMultibyte(&buf.pData_[0],1); + } + if(!bDataWritten) io_->seek(2,BasicIo::cur); + bDataWritten = true; + } else if (d->currentStream_ == Audio){ + if(xmpData_["Xmp.audio.MediaLanguage"].count() > 0){ + rtd = find(revTagDetails,xmpData_["Xmp.audio.MediaLanguage"].toString()); + if(rtd){ + buf = returnBuf(rtd->val_,2); + bDataWritten = writeMultibyte(buf.pData_,2); + } + } + if(!bDataWritten) io_->seek(2,BasicIo::cur); + bDataWritten = false; - for (int i = 0; size/4 != 0 ; size -=4, i++) { - io_->read(buf.pData_, 4); + if(xmpData_["Xmp.audio.Quality"].count() >0){ + buf = returnBuf((uint64_t)xmpData_["Xmp.audio.Quality"].toLong(),2); + bDataWritten = writeMultibyte(&buf.pData_[1],1); + bDataWritten = writeMultibyte(&buf.pData_[0],1); + } + } + if(!bDataWritten) io_->seek(2,BasicIo::cur); + bDataWritten = true; + break; + } + if(!bDataWritten) io_->seek(4, BasicIo::cur); + } + io_->seek(size%4,BasicIo::cur); + } +} - switch(i) { - case TrackHeaderVersion: - if(currentStream_ == Video) - xmpData_["Xmp.video.TrackHeaderVersion"] = returnBufValue(buf,1); - else if(currentStream_ == Audio) - xmpData_["Xmp.audio.TrackHeaderVersion"] = returnBufValue(buf,1); - break; - case TrackCreateDate: - //A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. - if(currentStream_ == Video) - xmpData_["Xmp.video.TrackCreateDate"] = returnUnsignedBufValue(buf); - else if(currentStream_ == Audio) - xmpData_["Xmp.audio.TrackCreateDate"] = returnUnsignedBufValue(buf); - break; - case TrackModifyDate: - //A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. - if(currentStream_ == Video) - xmpData_["Xmp.video.TrackModifyDate"] = returnUnsignedBufValue(buf); - else if(currentStream_ == Audio) - xmpData_["Xmp.audio.TrackModifyDate"] = returnUnsignedBufValue(buf); - break; - case TrackID: - if(currentStream_ == Video) - xmpData_["Xmp.video.TrackID"] = returnBufValue(buf); - else if(currentStream_ == Audio) - xmpData_["Xmp.audio.TrackID"] = returnBufValue(buf); - break; - case TrackDuration: - if(currentStream_ == Video) - xmpData_["Xmp.video.TrackDuration"] = returnBufValue(buf)/timeScale_; - else if(currentStream_ == Audio) - xmpData_["Xmp.audio.TrackDuration"] = returnBufValue(buf)/timeScale_; - break; - case TrackLayer: - if(currentStream_ == Video) - xmpData_["Xmp.video.TrackLayer"] = returnBufValue(buf, 2); - else if(currentStream_ == Audio) - xmpData_["Xmp.audio.TrackLayer"] = returnBufValue(buf, 2); - break; - case TrackVolume: - if(currentStream_ == Video) - xmpData_["Xmp.video.TrackVolume"] = (returnBufValue(buf, 1) + (buf.pData_[2] * 0.1)) * 100; - else if(currentStream_ == Audio) - xmpData_["Xmp.video.TrackVolume"] = (returnBufValue(buf, 1) + (buf.pData_[2] * 0.1)) * 100; - break; - case ImageWidth: - if(currentStream_ == Video) { - temp = returnBufValue(buf, 2) + static_cast((buf.pData_[2] * 256 + buf.pData_[3]) * 0.01); +void QuickTimeVideo::trackHeaderDecoder(uint32_t size) +{ + DataBuf buf(5); + int64_t temp = 0; + + if(!d->m_modifyMetadata){ + for (int32_t i = 0; size/4 != 0 ; size -=4, i++){ + + switch(i){ + case TrackHeaderVersion: readAudVidData("TrackHeaderVersion", 1, 1, 0); break; + case TrackCreateDate://A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. + readAudVidData("TrackCreateDate", 4, 1, 1); break; + case TrackModifyDate: //A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. + readAudVidData("TrackModifyDate", 4, 1, 1); break; + case TrackID: readAudVidData("TrackID", 4, 1, 0); break; + case TrackDuration: readAudVidData("TrackDuration", 4, (double)(1000/(double)d->timeScale_), 0); break; + case TrackLayer: readAudVidData("TrackLayer", 2, 1, 0); break; + case TrackVolume: readAudVidData("TrackVolume", 2, (double)(1/(double)2), 0); break; + case ImageWidth: io_->read(buf.pData_, 4); + if(d->currentStream_ == Video){ + temp = (returnBufValue(buf, 4)/(256*256)); xmpData_["Xmp.video.Width"] = temp; - width_ = temp; + d->width_ = temp; } break; - case ImageHeight: - if(currentStream_ == Video) { - temp = returnBufValue(buf, 2) + static_cast((buf.pData_[2] * 256 + buf.pData_[3]) * 0.01); + + case ImageHeight: io_->read(buf.pData_, 4); + if(d->currentStream_ == Video){ + temp = (returnBufValue(buf, 4)/(256*256)); xmpData_["Xmp.video.Height"] = temp; - height_ = temp; + d->height_ = temp; } break; - default: - break; + default: io_->seek(4 ,BasicIo::cur); break; } } io_->read(buf.pData_, size%4); - } // QuickTimeVideo::trackHeaderDecoder - void QuickTimeVideo::movieHeaderDecoder(unsigned long size) { - DataBuf buf(5); - std::memset(buf.pData_, 0x0, buf.size_); - buf.pData_[4] = '\0'; + } else { + for (int32_t i = 0; size/4 != 0 ; size -=4, i++){ + bool bDataWritten = false; + bool bVideo = d->currentStream_ == Video; + switch(i){ + case TrackHeaderVersion: bDataWritten = writeAudVidData("TrackHeaderVersion", 1, 1, 3, 0); break; + case TrackCreateDate: bDataWritten = writeAudVidData("TrackCreateDate", 1, 4, 0, 1) ; break; + case TrackModifyDate: bDataWritten = writeAudVidData("TrackModifyDate", 1, 4, 0, 1) ; break; + case TrackID: bDataWritten = writeAudVidData("TrackID", 1, 4, 0, 0) ; break; + case TrackDuration: bDataWritten = writeAudVidData("TrackDuration", (double)(d->timeScale_/1000), 4, 0, 0); break; + case TrackLayer: bDataWritten = writeAudVidData("TrackLayer", 11, 2, 2, 0) ; break; + case TrackVolume: bDataWritten = writeAudVidData("TrackVolume", 2, 2, 2, 0) ; break; + case ImageWidth: if( bVideo ) bDataWritten = writeAudVidData("Width", (256*256), 4, 0, 0) ; break; + case ImageHeight:if( bVideo ) bDataWritten = writeAudVidData("Height", (256*256), 4, 0, 0) ; break; + } + if(!bDataWritten) io_->seek(4,BasicIo::cur); + } + io_->read(buf.pData_, size%4); + } +} - for (int i = 0; size/4 != 0 ; size -=4, i++) { +bool QuickTimeVideo::writeAudVidData +( std::string sXmpTag, double iMulFactor, int64_t iBytCnt, int64_t iOffset, int64_t iRetFuncCall) +{ + DataBuf buf(5); + bool bRetVal = false; + int64_t iXmpTagVal = 0; + + if(d->currentStream_ == Video){ + if(xmpData_["Xmp.video." + sXmpTag].count() > 0){ + iXmpTagVal = xmpData_["Xmp.video." + sXmpTag].toLong()*iMulFactor; + if(iRetFuncCall == 0) buf = returnBuf(iXmpTagVal, iBytCnt); + else buf = returnUnsignedBuf(iXmpTagVal); + bRetVal = writeMultibyte(buf.pData_, iBytCnt ,iOffset); + } + } + else if(d->currentStream_ == Audio){ + if(xmpData_["Xmp.audio." + sXmpTag].count() > 0){ + iXmpTagVal = xmpData_["Xmp.audio." + sXmpTag].toLong()*iMulFactor; + if(iRetFuncCall == 0) buf = returnBuf(iXmpTagVal, iBytCnt); + else buf = returnUnsignedBuf(iXmpTagVal); + bRetVal = writeMultibyte(buf.pData_, iBytCnt ,iOffset); + } + } + return bRetVal; +} + +void QuickTimeVideo::readAudVidData(std::string sTag, int32_t iNumRdBytes, double dMulFact ,int32_t iFunc2Call){ + DataBuf buf(5); + io_->read(buf.pData_, 4); + if(d->currentStream_ == Video){ + if(iFunc2Call == 0) xmpData_["Xmp.video."+ sTag] = (int64_t)(returnBufValue(buf, iNumRdBytes) * dMulFact) ; + else if(iFunc2Call == 1) xmpData_["Xmp.video."+ sTag] = (uint64_t)(returnUnsignedBufValue(buf, iNumRdBytes) * dMulFact); + } + else if(d->currentStream_ == Audio){ + if(iFunc2Call == 0) xmpData_["Xmp.audio."+ sTag] = (int64_t)(returnBufValue(buf, iNumRdBytes) * dMulFact); + else if(iFunc2Call == 1)xmpData_["Xmp.audio."+ sTag] = (uint64_t)(returnUnsignedBufValue(buf, iNumRdBytes) * dMulFact); + } +} + +void QuickTimeVideo::readAudVidStrData(std::string sTag, int32_t iNumRdBytes){ + DataBuf buf(iNumRdBytes); + io_->read(buf.pData_, iNumRdBytes); + if(d->currentStream_ == Video) xmpData_["Xmp.video."+ sTag] = Exiv2::toString(buf.pData_); + else if(d->currentStream_ == Audio) xmpData_["Xmp.audio."+ sTag] = Exiv2::toString(buf.pData_); +} + +void QuickTimeVideo::readStrData(std::string sTag, int32_t iNumRdBytes){ + DataBuf buf(iNumRdBytes); + io_->read(buf.pData_, iNumRdBytes); + xmpData_[sTag] = Exiv2::toString(buf.pData_); +} + +void QuickTimeVideo::movieHeaderDecoder(uint32_t size) +{ + DataBuf buf(5); + + if(!d->m_modifyMetadata){ + for (int32_t i = 0; size/4 != 0 ; size -=4, i++){ io_->read(buf.pData_, 4); - - switch(i) { - case MovieHeaderVersion: - xmpData_["Xmp.video.MovieHeaderVersion"] = returnBufValue(buf,1); break; - case CreateDate: - //A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. - xmpData_["Xmp.video.DateUTC"] = returnUnsignedBufValue(buf); break; - case ModifyDate: - //A 32-bit integer that specifies (in seconds since midnight, January 1, 1904) when the movie atom was created. - xmpData_["Xmp.video.ModificationDate"] = returnUnsignedBufValue(buf); break; + switch(i){ + case MovieHeaderVersion: xmpData_["Xmp.video.MovieHeaderVersion"] = returnBufValue(buf,1) ; break; + case CreateDate: xmpData_["Xmp.video.DateUTC"] = returnUnsignedBufValue(buf) ; break; + case ModifyDate: xmpData_["Xmp.video.ModificationDate"] = returnUnsignedBufValue(buf) ; break; + case Duration: xmpData_["Xmp.video.Duration"] = (int64_t)((double)returnBufValue(buf) + * (double)1000/ (double)d->timeScale_); break; + case PreferredRate: xmpData_["Xmp.video.PreferredRate"] = returnBufValue(buf, 4)/(256*256) ; break; + case PreferredVolume: xmpData_["Xmp.video.PreferredVolume"] = (returnUnsignedBufValue(buf, 2)/2) ; break; + case PreviewTime: xmpData_["Xmp.video.PreviewTime"] = (int64_t)((double)returnBufValue(buf) + * (double)1000/ (double)d->timeScale_); break; + case PreviewDuration: xmpData_["Xmp.video.PreviewDuration"] = (int64_t)((double)returnBufValue(buf) + * (double)1000/ (double)d->timeScale_); break; + case PosterTime: xmpData_["Xmp.video.PosterTime"] = returnBufValue(buf) ; break; + case SelectionTime: xmpData_["Xmp.video.SelectionTime"] = returnBufValue(buf) ; break; + case SelectionDuration: xmpData_["Xmp.video.SelectionDuration"] = returnBufValue(buf)*1000/ d->timeScale_; break; + case CurrentTime: xmpData_["Xmp.video.CurrentTime"] = returnBufValue(buf) ; break; + case NextTrackID: xmpData_["Xmp.video.NextTrackID"] = returnBufValue(buf) ; break; case TimeScale: xmpData_["Xmp.video.TimeScale"] = returnBufValue(buf); - timeScale_ = returnBufValue(buf); break; - case Duration: - if(timeScale_ != 0) // To prevent division by zero - xmpData_["Xmp.video.Duration"] = returnBufValue(buf) * 1000 / timeScale_; break; - case PreferredRate: - xmpData_["Xmp.video.PreferredRate"] = returnBufValue(buf, 2) + ((buf.pData_[2] * 256 + buf.pData_[3]) * 0.01); break; - case PreferredVolume: - xmpData_["Xmp.video.PreferredVolume"] = (returnBufValue(buf, 1) + (buf.pData_[2] * 0.1)) * 100; break; - case PreviewTime: - xmpData_["Xmp.video.PreviewTime"] = returnBufValue(buf); break; - case PreviewDuration: - xmpData_["Xmp.video.PreviewDuration"] = returnBufValue(buf); break; - case PosterTime: - xmpData_["Xmp.video.PosterTime"] = returnBufValue(buf); break; - case SelectionTime: - xmpData_["Xmp.video.SelectionTime"] = returnBufValue(buf); break; - case SelectionDuration: - xmpData_["Xmp.video.SelectionDuration"] = returnBufValue(buf); break; - case CurrentTime: - xmpData_["Xmp.video.CurrentTime"] = returnBufValue(buf); break; - case NextTrackID: - xmpData_["Xmp.video.NextTrackID"] = returnBufValue(buf); break; - default: + d->timeScale_ = returnBufValue(buf); break; } } io_->read(buf.pData_, size%4); - } // QuickTimeVideo::movieHeaderDecoder + } else { + for (int32_t i = 0; size/4 != 0 ; size -=4, i++){ + bool bDataWritten = false; + std::memset(buf.pData_, 0x0, buf.size_); + switch(i){ + //Fixme:There are known roundoff error while typecasting the number to int64_t + //for example Duration (double to int64_t) + case MovieHeaderVersion: + if(xmpData_["Xmp.video.MovieHeaderVersion"].count() > 0){ + int64_t movieHeaderVersion = (int64_t)xmpData_["Xmp.video.MovieHeaderVersion"].toLong(); + buf = returnBuf(movieHeaderVersion,1); + bDataWritten = writeMultibyte(&buf.pData_[0], 1, 3); + } + break; - void QuickTimeVideo::aspectRatio() - { - //TODO - Make a better unified method to handle all cases of Aspect Ratio + case CreateDate: + if(xmpData_["Xmp.video.DateUTC"].count() > 0){ + uint64_t dateUTC = (uint64_t)xmpData_["Xmp.video.DateUTC"].toLong(); + buf = returnUnsignedBuf(dateUTC); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; - double aspectRatio = (double)width_ / (double)height_; - aspectRatio = floor(aspectRatio*10) / 10; - xmpData_["Xmp.video.AspectRatio"] = aspectRatio; + case ModifyDate: + if(xmpData_["Xmp.video.ModificationDate"].count() > 0){ + uint64_t modificationDate = (uint64_t)xmpData_["Xmp.video.ModificationDate"].toLong(); + buf = returnUnsignedBuf(modificationDate); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; - int aR = (int) ((aspectRatio*10.0)+0.1); + case TimeScale: + if(xmpData_["Xmp.video.TimeScale"].count() > 0){ + io_->read(buf.pData_,4); + d->timeScale_ = returnBufValue(buf); + io_->seek(-4,BasicIo::cur); + int64_t tmpTimeScale = (int64_t)xmpData_["Xmp.video.TimeScale"].toLong(); + buf = returnBuf(tmpTimeScale); + bDataWritten = writeMultibyte(buf.pData_,4); + } else { + io_->read(buf.pData_,4); + d->timeScale_ = returnBufValue(buf); + bDataWritten = true; + } + break; - switch (aR) { - case 13 : xmpData_["Xmp.video.AspectRatio"] = "4:3" ; break; - case 17 : xmpData_["Xmp.video.AspectRatio"] = "16:9" ; break; - case 10 : xmpData_["Xmp.video.AspectRatio"] = "1:1" ; break; - case 16 : xmpData_["Xmp.video.AspectRatio"] = "16:10" ; break; - case 22 : xmpData_["Xmp.video.AspectRatio"] = "2.21:1" ; break; - case 23 : xmpData_["Xmp.video.AspectRatio"] = "2.35:1" ; break; - case 12 : xmpData_["Xmp.video.AspectRatio"] = "5:4" ; break; - default : xmpData_["Xmp.video.AspectRatio"] = aspectRatio;break; - } - } // QuickTimeVideo::aspectRatio + case Duration: + if(xmpData_["Xmp.video.Duration"].count() > 0){ + int64_t duration = (int64_t)((double)xmpData_["Xmp.video.Duration"]. + toLong()*(double)d->timeScale_/(double)1000); + buf = returnBuf(duration); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; + case PreferredRate: + if(xmpData_["Xmp.video.PreferredRate"].count() > 0){ + buf = returnBuf((int64_t)xmpData_["Xmp.video.PreferredRate"].toLong() + *(256*256),4); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; - Image::AutoPtr newQTimeInstance(BasicIo::AutoPtr io, bool /*create*/) { - Image::AutoPtr image(new QuickTimeVideo(io)); - if (!image->good()) { - image.reset(); + case PreferredVolume: + if(xmpData_["Xmp.video.PreferredVolume"].count() > 0){ + uint64_t preferredVolume = (uint64_t)(xmpData_["Xmp.video.PreferredVolume"] + .toLong()*2);//128 = 100% + buf = returnBuf(preferredVolume,2); + bDataWritten = writeMultibyte(buf.pData_, 2, 2); + } + break; + + case PreviewTime: + if(xmpData_["Xmp.video.PreviewTime"].count() > 0){ + int64_t previewTime = (int64_t)((double)xmpData_["Xmp.video.PreviewTime"].toLong() + *(double)d->timeScale_/(double)1000);//1024= 1 second + buf = returnBuf(previewTime); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; + + case PreviewDuration: + if(xmpData_["Xmp.video.PreviewDuration"].count() > 0){ + int64_t previewDuration = (int64_t)((double)xmpData_["Xmp.video.PreviewDuration"] + .toLong()*(double)d->timeScale_/(double)1000); + buf = returnBuf(previewDuration); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; + + case PosterTime: + if(xmpData_["Xmp.video.PosterTime"].count() > 0){ + int64_t posterTime = (int64_t)xmpData_["Xmp.video.PosterTime"].toLong(); + buf = returnBuf(posterTime); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; + + case SelectionTime: + if(xmpData_["Xmp.video.SelectionTime"].count() > 0){ + int64_t selectionTime = (int64_t)xmpData_["Xmp.video.SelectionTime"].toLong(); + buf = returnBuf(selectionTime); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; + + case SelectionDuration: + if(xmpData_["Xmp.video.SelectionDuration"].count() > 0){ + int64_t selectionDuration = (int64_t)((double)xmpData_["Xmp.video.SelectionDuration"] + .toLong()*(double)d->timeScale_/(double)1000); + buf = returnBuf(selectionDuration); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; + + case CurrentTime: + if(xmpData_["Xmp.video.CurrentTime"].count() > 0){ + int64_t currentTime = (int64_t)xmpData_["Xmp.video.CurrentTime"].toLong(); + buf = returnBuf(currentTime); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; + + case NextTrackID: + if(xmpData_["Xmp.video.NextTrackID"].count() > 0){ + int64_t nextTrackID = (int64_t)xmpData_["Xmp.video.NextTrackID"].toLong(); + buf = returnBuf(nextTrackID); + bDataWritten = writeMultibyte(buf.pData_,4); + } + break; + } + if(!bDataWritten) io_->seek(4, BasicIo::cur); } - return image; + io_->seek(size%4,BasicIo::cur); + } +} + +void QuickTimeVideo::aspectRatio() +{ + //TODO - Make a better unified method to handle all cases of Aspect Ratio + + double aspectRatio = (double)d->width_ / (double)d->height_; + aspectRatio = floor(aspectRatio*10) / 10; + xmpData_["Xmp.video.AspectRatio"] = aspectRatio; + + int32_t aR = (int32_t) ((aspectRatio*10.0)+0.1); + + switch (aR) { + case 13 : xmpData_["Xmp.video.AspectRatio"] = "4:3" ; break; + case 17 : xmpData_["Xmp.video.AspectRatio"] = "16:9" ; break; + case 10 : xmpData_["Xmp.video.AspectRatio"] = "1:1" ; break; + case 16 : xmpData_["Xmp.video.AspectRatio"] = "16:10" ; break; + case 22 : xmpData_["Xmp.video.AspectRatio"] = "2.21:1" ; break; + case 23 : xmpData_["Xmp.video.AspectRatio"] = "2.35:1" ; break; + case 12 : xmpData_["Xmp.video.AspectRatio"] = "5:4" ; break; + default : xmpData_["Xmp.video.AspectRatio"] = aspectRatio;break; // needed? + } +} + +void QuickTimeVideo::reverseTagDetails +(const TagDetails inputTagVocabulary[], RevTagDetails outputTagVocabulary[] ,int32_t size) +{ + for (int32_t i=0; igood()) image.reset(); + return image; +} + +void QuickTimeVideo::writeStringData(Exiv2::Xmpdatum xmpStringData, int32_t size, int32_t skipOffset) +{ + if(xmpStringData.count() > 0){ + std::string dataString = xmpStringData.toString(); + Exiv2::byte* rawData = new byte[(uint8_t)size]; + int32_t newSize = (int32_t)dataString.size(); + + for(int32_t i=0; iwrite(rawData,size); + io_->seek((int)skipOffset,BasicIo::cur); + delete[] rawData; + } else io_->seek((size+skipOffset),BasicIo::cur); +} + +void QuickTimeVideo::writeLongData(Exiv2::Xmpdatum xmpIntData, int32_t size, int32_t skipOffset) +{ + if(xmpIntData.count() > 0){ + int32_t rawIntData = (int32_t)xmpIntData.toLong(); + io_->write((Exiv2::byte*)&rawIntData,size); + io_->seek(skipOffset,BasicIo::cur); + } + else io_->seek((size+skipOffset),BasicIo::cur); +} + +void QuickTimeVideo::writeShortData(Exiv2::Xmpdatum xmpIntData, int16_t size, int32_t skipOffset) +{ + if(xmpIntData.count() > 0){ + int16_t rawIntData = (int16_t)xmpIntData.toLong(); + io_->write((Exiv2::byte*)&rawIntData,size); + io_->seek(skipOffset,BasicIo::cur); + } + else io_->seek((size+skipOffset),BasicIo::cur); +} + +/*! + * \brief QuickTimeVideo::writeMultibyte Write data directly from acurrent position of basicIo poiter with the bRawData upto size number of bytes + * and then skips iOffset bytes. + * \param bRawData + * \param iSize + * \param iOffset + * \return + */ +bool QuickTimeVideo::writeMultibyte(Exiv2::byte * bRawData ,int64_t iSize, int64_t iOffset) +{ + int32_t iCurrPos = io_->tell(); + if (iSize != 0 && bRawData != NULL){ + if ((io_->write(bRawData, iSize) > 0)) io_->seek(iOffset , BasicIo::cur); + else io_->seek(iCurrPos + iSize + iOffset, BasicIo::beg); + } + else io_->seek(iCurrPos + iOffset, BasicIo::beg); + + //Return value is just for assignment to a variable at calling location. + return true; +} + +void QuickTimeVideo::writeApertureData(Exiv2::Xmpdatum xmpApertureData, int16_t size, int32_t skipOffset) +{ + if(xmpApertureData.count() >0){ + Exiv2::byte rawApertureData[4]; + Exiv2::byte rawApertureDataTmp[2]; + const std::string apertureData = xmpApertureData.toString(); + vector apertureDataValue = getNumberFromString(apertureData,'.'); + memcpy(rawApertureDataTmp,&apertureDataValue.at(0),2); + rawApertureData[0] = rawApertureDataTmp[0]; + rawApertureData[1] = rawApertureDataTmp[1]; + memcpy(rawApertureDataTmp,&apertureDataValue.at(1),2); + rawApertureData[2] = rawApertureDataTmp[0]; + rawApertureData[3] = rawApertureDataTmp[1]; + io_->write(rawApertureData,size); + io_->seek(skipOffset,BasicIo::cur); + } + else io_->seek((size+skipOffset),BasicIo::cur); +} + +/*! + * \brief isQTimeType Cheecks if file belongs to Quicktime container type. + * \param iIo + * \param advance + * \return + */ +bool isQTimeType(BasicIo& iIo, bool advance){ + const int32_t len = 4; + Exiv2::byte* buf = new byte[len]; + iIo.read(buf, len); + iIo.read(buf, len); + + if (iIo.error() || iIo.eof()){ + delete[] buf; + return false; } - bool isQTimeType(BasicIo& iIo, bool advance) { - const int32_t len = 4; - byte buf[len]; - iIo.read(buf, len); - iIo.read(buf, len); - - if (iIo.error() || iIo.eof()) { - return false; - } - - bool matched = isQuickTimeType(buf[0], buf[1], buf[2], buf[3]); - if (!advance || !matched) { - iIo.seek(static_cast(0), BasicIo::beg); - } - - return matched; - } - -} // namespace Exiv2 - + bool matched = isQuickTimeType(buf[0], buf[1], buf[2], buf[3]); + if (!advance || !matched) iIo.seek(static_cast(0), BasicIo::beg); + delete[] buf; + return matched; +} // isQTimeType +} // namespace Exiv2 diff --git a/src/quicktimevideo.hpp b/src/quicktimevideo.hpp index 9a8b1d47..4ae2ef45 100644 --- a/src/quicktimevideo.hpp +++ b/src/quicktimevideo.hpp @@ -22,13 +22,16 @@ @file quicktimevideo.hpp @brief An Image subclass to support Quick Time video files @version $Rev$ - @author Abhinav Badola for GSoC 2012 + @authors Abhinav Badola for GSoC 2012 mail.abu.to@gmail.com + Mahesh Hegde for GSoC 2013 + maheshmhegade@gmail.com @date 28-Jun-12, AB: created */ #ifndef QUICKTIMEVIDEO_HPP #define QUICKTIMEVIDEO_HPP - +#include +using namespace std; // ***************************************************************************** // included header files #include "exif.hpp" @@ -42,20 +45,36 @@ namespace Exiv2 { // ***************************************************************************** // class definitions - // Add qtime to the supported image formats - namespace ImageType { - const int qtime = 22; //!< Treating qtime as an image type> - } +// Add qtime to the supported image formats +namespace ImageType { +const int qtime = 22; //!< Treating qtime as an image type> +} - /*! +/*! @brief Class to access QuickTime video files. */ - class EXIV2API QuickTimeVideo:public Image +class EXIV2API QuickTimeVideo:public Image +{ +public: + /*! + * \brief The QuickAtom class: + *Object of this class is intended to contain data about the premitive atom inside + *any atom + */ + class QuickAtom { public: - //! @name Creators - //@{ - /*! + QuickAtom(){} + ~QuickAtom(){} + public: + byte m_AtomId[5]; //!< Id of the Atom. + unsigned long m_AtomLocation; //!< Location of atom inside a file + unsigned long m_AtomSize; //!< Size of atom + }; +public: + //! @name Creators + //@{ + /*! @brief Constructor for a QuickTime video. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @@ -66,27 +85,28 @@ namespace Exiv2 { instance after it is passed to this method. Use the Image::io() method to get a temporary reference. */ - QuickTimeVideo(BasicIo::AutoPtr io); - //@} + QuickTimeVideo(BasicIo::AutoPtr io); + //@} - //! @name Manipulators - //@{ - void readMetadata(); - void writeMetadata(); - //@} + ~QuickTimeVideo(); + //! @name Manipulators + //@{ + void readMetadata(); + void writeMetadata(); + //@} - //! @name Accessors - //@{ - std::string mimeType() const; - //@} + //! @name Accessors + //@{ + std::string mimeType() const; + //@} - protected: - /*! +protected: + /*! @brief Check for a valid tag and decode the block at the current IO position. Calls tagDecoder() or skips to next tag, if required. */ - void decodeBlock(); - /*! + void decodeBlock(); + /*! @brief Interpret tag information, and call the respective function to save it in the respective XMP container. Decodes a Tag Information and saves it in the respective XMP container, if @@ -94,159 +114,236 @@ namespace Exiv2 { @param buf Data buffer which cotains tag ID. @param size Size of the data block used to store Tag Information. */ - void tagDecoder(Exiv2::DataBuf & buf, unsigned long size); + void tagDecoder(Exiv2::DataBuf & buf, uint32_t size); - private: - /*! +private: + /*! @brief Interpret file type of the video, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void fileTypeDecoder(unsigned long size); - /*! + void fileTypeDecoder(uint32_t size); + /*! @brief Interpret Media Header Tag, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void mediaHeaderDecoder(unsigned long size); - /*! + void mediaHeaderDecoder(uint32_t size); + /*! @brief Interpret Video Header Tag, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void videoHeaderDecoder(unsigned long size); - /*! + void videoHeaderDecoder(uint32_t size); + /*! @brief Interpret Movie Header Tag, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void movieHeaderDecoder(unsigned long size); - /*! + void movieHeaderDecoder(uint32_t size); + /*! @brief Interpret Track Header Tag, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void trackHeaderDecoder(unsigned long size); - /*! + void trackHeaderDecoder(uint32_t size); + /*! @brief Interpret Handler Tag, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void handlerDecoder(unsigned long size); - /*! + void handlerDecoder(uint32_t size); + /*! @brief Interpret Tag which contain other sub-tags, and save it in the respective XMP container. */ - void multipleEntriesDecoder(); - /*! + void multipleEntriesDecoder(uint32_t iDummySize); + /*! @brief Interpret Sample Description Tag, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void sampleDesc(unsigned long size); - /*! + void sampleDesc(uint32_t size); + /*! @brief Interpret Image Description Tag, and save it in the respective XMP container. */ - void imageDescDecoder(); - /*! + void imageDescDecoder(); + /*! @brief Interpret User Data Tag, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void userDataDecoder(unsigned long size); - /*! + void userDataDecoder(uint32_t size); + /*! @brief Interpret Preview Tag, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void previewTagDecoder(unsigned long size); - /*! + void previewTagDecoder(uint32_t size); + /*! @brief Interpret Meta Keys Tags, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void keysTagDecoder(unsigned long size); - /*! + void keysTagDecoder(uint32_t size); + /*! @brief Interpret Track Aperture Tags, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void trackApertureTagDecoder(unsigned long size); - /*! + void trackApertureTagDecoder(uint32_t size); + /*! @brief Interpret Nikon Tag, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void NikonTagsDecoder(unsigned long size); - /*! + void NikonTagsDecoder(uint32_t size); + /*! @brief Interpret Tags from Different Camera make, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void CameraTagsDecoder(unsigned long size); - /*! + void CameraTagsDecoder(uint32_t size); + /*! @brief Interpret Audio Description Tag, and save it in the respective XMP container. */ - void audioDescDecoder(); - /*! + void audioDescDecoder(); + /*! @brief Helps to calculate Frame Rate from timeToSample chunk, and save it in the respective XMP container. */ - void timeToSampleDecoder(); - /*! + void timeToSampleDecoder(uint32_t iDummySize); + /*! @brief Recognizes which stream is currently under processing, and save its information in currentStream_ . */ - void setMediaStream(); - /*! - @brief Used to discard a tag along with its data. The Tag will - be skipped and not decoded. - @param size Size of the data block that is to skipped. - */ - void discard(unsigned long size); - /*! + void setMediaStream(uint32_t iDummySize); + /*! @brief Calculates Aspect Ratio of a video, and stores it in the respective XMP container. */ - void aspectRatio(); + void aspectRatio(); + /*! + * \brief reverseTagDetails + * \param inputTagVocabulary + * \param outputTagVocabulary + * \param size + */ + void reverseTagDetails(const Internal::TagDetails inputTagVocabulary[], + Internal::RevTagDetails outputTagVocabulary[] , int32_t size); - private: - //! @name NOT Implemented - //@{ - //! Copy constructor - QuickTimeVideo(const QuickTimeVideo& rhs); - //! Assignment operator - QuickTimeVideo& operator=(const QuickTimeVideo& rhs); - //@} +private: + //! @name NOT Implemented + //@{ + //! Copy constructor + QuickTimeVideo(const QuickTimeVideo& rhs); + //! Assignment operator + QuickTimeVideo& operator=(const QuickTimeVideo& rhs); + //@} + /*! + @brief Provides the main implementation of writeMetadata() by + writing all buffered metadata to the provided BasicIo. + @param oIo BasicIo instance to write to (a temporary location). - private: - //! Variable which stores Time Scale unit, used to calculate time. - uint64_t timeScale_; - //! Variable which stores current stream being processsed. - int currentStream_; - //! Variable to check the end of metadata traversing. - bool continueTraversing_; - //! Variable to store height and width of a video frame. - uint64_t height_, width_; + @return 4 if opening or writing to the associated BasicIo fails + */ + EXV_DLLLOCAL void doWriteMetadata(); + /*! + * \brief findAtomPositions + * \param atomId + * \return all the locations where atoms with atomId exist. + */ + std::vector< pair > findAtomPositions(const char *atomId); - }; //QuickTimeVideo End + /*! + * \brief writeStringData + * \param xmpStringData + * \param size + * \param skipOffset + */ + void writeStringData(Exiv2::Xmpdatum xmpStringData, int32_t size, int32_t skipOffset=0); + + /*! + * \brief writeLongData + * \param xmpIntData + * \param size + * \param skipOffset + */ + void writeLongData(Exiv2::Xmpdatum xmpIntData, int32_t size=4, int32_t skipOffset=0); + + /*! + * \brief writeShortData + * \param xmpIntData + * \param size + * \param skipOffset + */ + void writeShortData(Exiv2::Xmpdatum xmpIntData, int16_t size=2, int32_t skipOffset=0); + + /*! + * \brief writeMultibyte + * \param bRawData + * \param size + */ + bool writeMultibyte(Exiv2::byte * bRawData = NULL , int64_t iSize = 0, int64_t iOffset = 0); + + /*! + * \brief writeApertureData + * \param xmpIntData + * \param size + * \param skipOffset + */ + void writeApertureData(Exiv2::Xmpdatum xmpIntData, int16_t size, int32_t skipOffset=0); + + /*! + * \brief writeAudVidData + * \param iTagType + * \return + */ + bool writeAudVidData(int64_t iTagType); + + /*! + * \brief writeAudVidData + * \param sXmpTag + * \param iOffset + * \return + */ + bool writeAudVidData( std::string sXmpTag, double iMulFactor, int64_t iBytCnt, int64_t iOffset, int64_t iRetFuncCall); + + /*! + * \brief readAudVidData + * \param sTag + * \param iNumRdBytes + * \param dMulFact + * \param iFunc2Call + */ + void readAudVidData(std::string sTag, int32_t iNumRdBytes, double dMulFact ,int32_t iFunc2Call); + + void readAudVidStrData(std::string sTag, int32_t iNumRdBytes); + void readStrData(std::string sTag, int32_t iNumRdBytes); + +private: + + class Private; + Private * const d; + +}; //QuickTimeVideo End // ***************************************************************************** // template, inline and free functions - // These could be static private functions on Image subclasses but then - // ImageFactory needs to be made a friend. - /*! +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! @brief Create a new QuicktimeVideo instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ - EXIV2API Image::AutoPtr newQTimeInstance(BasicIo::AutoPtr io, bool create); +EXIV2API Image::AutoPtr newQTimeInstance(BasicIo::AutoPtr io, bool create); - //! Check if the file iIo is a Quick Time Video. - EXIV2API bool isQTimeType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a Quick Time Video. +EXIV2API bool isQTimeType(BasicIo& iIo, bool advance); } // namespace Exiv2 diff --git a/src/riffvideo.cpp b/src/riffvideo.cpp index 0dcd291c..b8a424b8 100644 --- a/src/riffvideo.cpp +++ b/src/riffvideo.cpp @@ -1,6 +1,6 @@ // ***************************************************************** -*- C++ -*- /* - * Copyright (C) 2004-2013 Andreas Huggel + * Copyright (C) 2004-2012 Andreas Huggel * * This program is part of the Exiv2 distribution. * @@ -22,6 +22,7 @@ File: riffvideo.cpp Version: $Rev$ Author(s): Abhinav Badola for GSoC 2012 (AB) + Mahesh Hegde for GSoC 2013 mailto:maheshmhegade at gmail dot com History: 18-Jun-12, AB: created Credits: See header file */ @@ -38,18 +39,21 @@ EXIV2_RCSID("@(#) $Id$") #include "tags_int.hpp" #include "types.hpp" #include "tiffimage_int.hpp" +#include "string.h" +#include "utilsvideo.hpp" + // + standard includes #include // ***************************************************************************** // class member definitions -namespace Exiv2 { - namespace Internal { +namespace Exiv2{ + namespace Internal{ /*! @brief Dummy TIFF header structure. */ - class DummyTiffHeader : public TiffHeaderBase { + class DummyTiffHeader : public TiffHeaderBase{ public: //! @name Creators //@{ @@ -62,26 +66,24 @@ namespace Exiv2 { //! @name Manipulators //@{ //! Dummy read function. Does nothing and returns true. - bool read(const byte* pData, uint32_t size); + bool read(const byte* pData, uint64_t size); //@} }; // class TiffHeader DummyTiffHeader::DummyTiffHeader(ByteOrder byteOrder) - : TiffHeaderBase(42, 0, byteOrder, 0) - { + : TiffHeaderBase(42, 0, byteOrder, 0){ } - DummyTiffHeader::~DummyTiffHeader() - { + DummyTiffHeader::~DummyTiffHeader(){ } - bool DummyTiffHeader::read(const byte* /*pData*/, uint32_t /*size*/) - { + bool DummyTiffHeader::read(const byte* /*pData*/, uint64_t /*size*/){ return true; } - extern const TagVocabulary infoTags[] = { + //! RIFF INFO tags supported Under Exiv2. + extern const TagVocabulary infoTags[] ={ { "AGES", "Xmp.video.Rated" }, { "CMNT", "Xmp.video.Comment" }, { "CODE", "Xmp.video.EncodedBy" }, @@ -168,7 +170,8 @@ namespace Exiv2 { { "YEAR", "Xmp.video.Year" } }; - extern const TagDetails audioEncodingValues[] = { + //! Audio Encoding Information. + extern const TagDetails audioEncodingValues[] ={ { 0x1, "Microsoft PCM" }, { 0x2, "Microsoft ADPCM" }, { 0x3, "Microsoft IEEE float" }, @@ -414,7 +417,8 @@ namespace Exiv2 { { 0xffff, "Development" } }; - extern const TagDetails nikonAVITags[] = { + //! Nikon tags. + extern const TagDetails nikonAVITags[] ={ { 0x0003, "Xmp.video.Make" }, { 0x0004, "Xmp.video.Model" }, { 0x0005, "Xmp.video.Software" }, @@ -452,7 +456,8 @@ namespace Exiv2 { { 8, "Rotate 270 CW" } }; */ - extern const TagDetails meteringMode[] = { + //! Metering tags. + extern const TagDetails meteringMode[] ={ { 0, "Unknown" }, { 1, "Average" }, { 2, "Center-weighted average" }, @@ -463,335 +468,624 @@ namespace Exiv2 { { 255, "Other" } }; - extern const TagDetails resolutionUnit[] = { + //!Resolution tag. + extern const TagDetails resolutionUnit[] ={ { 1, "None" }, { 2, "inches" }, { 3, "cm" } }; - /*! - @brief Function used to check equality of a Tags with a - particular string (ignores case while comparing). - @param buf Data buffer that will contain Tag to compare - @param str char* Pointer to string - @return Returns true if the buffer value is equal to string. - */ - bool equalsRiffTag(Exiv2::DataBuf& buf ,const char* str) { - for(int i = 0; i < 4; i++ ) - if(toupper(buf.pData_[i]) != str[i]) - return false; - return true; - } + int64_t i; //!< temporary variable. + int64_t j; //!< temporary variable. - enum streamTypeInfo { + //! To select specific bytes with in a chunk. + enum streamTypeInfo{ Audio = 1, MIDI, Text, Video }; - enum streamHeaderTags { + + //! To select specific bytes with in a chunk. + enum streamHeaderTags{ codec = 1, sampleRate = 5, sampleCount = 8, quality = 10, sampleSize }; - enum bmptags { + + //! To select specific bytes with in a chunk. + enum bmptags{ imageWidth, imageHeight, planes, bitDepth, compression, imageLength, pixelsPerMeterX, pixelsPerMeterY, numColors, numImportantColors }; - enum audioFormatTags { + + //! To select specific bytes with in a chunk. + enum audioFormatTags{ encoding, numberOfChannels, audioSampleRate, avgBytesPerSec = 4, bitsPerSample = 7 }; - enum aviHeaderTags { - frameRate, maxDataRate, frameCount = 4, streamCount = 6, imageWidth_h = 8, imageHeight_h + + //! To select specific bytes with in a chunk. + enum aviHeaderTags{ + frameRate, maxDataRate, frameCount = 4, initialFrames ,streamCount, suggestedBufferSize ,imageWidth_h, imageHeight_h }; -}} // namespace Internal, Exiv2 + } +} // namespace Internal, Exiv2 -namespace Exiv2 { - using namespace Exiv2::Internal; +namespace Exiv2{ +using namespace Exiv2::Internal; - RiffVideo::RiffVideo(BasicIo::AutoPtr io) - : Image(ImageType::riff, mdNone, io) - { - } // RiffVideo::RiffVideo +class RiffVideo::Private{ +public: + Private(){ + streamType_ = 0; + m_decodeMetaData = true; + } + //! Variable which stores current stream being processsed. + int streamType_; + //! Variable to decide whether to decode the metadata or just reveal file structure (Lists inside RIFF) + bool m_decodeMetaData; + //!variable to decide whether write metadata is possible or not (by default false) + bool m_modifyMetadata; + //!abstract metadata holding variable (its data about data about data!) + RiffMetaSkeleton m_riffFileSkeleton; +}; - std::string RiffVideo::mimeType() const - { - return "video/riff"; +RiffVideo::RiffVideo(BasicIo::AutoPtr io) + : Image(ImageType::riff, mdNone, io), d(new Private){ + d->m_modifyMetadata = false; + d->m_decodeMetaData = true; +} // RiffVideo::RiffVideo + +RiffVideo::~RiffVideo(){ + delete d; +} + +std::string RiffVideo::mimeType() const{ + return "video/riff"; +} + +/*! + * \brief RiffVideo::findChunkPositions: + * Return a list of chunk positions for a given chunk Id + * \param chunkId + * \return: if No chunk of chunkId exists,then size of returned + * vector will be zero + */ +std::vector RiffVideo::findChunkPositions(const char* chunkId){ + DataBuf chkId((uint64_t)5); + chkId.pData_[4] = '\0'; + uint64_t i; + + std::vector positions; + for ( i=0; im_riffFileSkeleton.m_primitiveChunks.size(); i++){ + io_->seek(d->m_riffFileSkeleton.m_primitiveChunks[i]->m_chunkLocation,BasicIo::beg); + io_->read(chkId.pData_,4); + if(UtilsVideo::compareTagValue(chkId,chunkId)) positions.push_back((int32_t)io_->tell()); + } + return positions; +} + +//Same as above but returns only header locations +std::vector RiffVideo::findHeaderPositions(const char* headerId){ + DataBuf hdrId((uint64_t)5); + hdrId.pData_[4] = '\0'; + uint64_t i; + + std::vector positions; + for (i=0;im_riffFileSkeleton.m_headerChunks.size();i++){ + io_->seek((d->m_riffFileSkeleton.m_headerChunks[i]->m_headerLocation + 4),BasicIo::beg); + io_->read(hdrId.pData_,4); + if(UtilsVideo::compareTagValue(hdrId,headerId)) positions.push_back((int32_t)io_->tell() - 8); + } + return positions; +} + +void RiffVideo::writeMetadata(){ + if (io_->open() != 0) throw Error(9, io_->path(), strError()); + IoCloser closer(*io_); + doWriteMetadata(); + io_->close(); + return; +} // RiffVideo::writeMetadata + +/*! + * \brief RiffVideo::doWriteMetadata: + * Search for all the supported ChunkIds in Exiv2 and + * write the modified data to the file. + */ +void RiffVideo::doWriteMetadata(){ + //pre-write checks to make sure that we are writing to provided Riff file only + if (!io_->isopen()) throw Error(20); + if (!isRiffType(*io_, false)){ + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "RIFF"); } - void RiffVideo::writeMetadata() - { - } // RiffVideo::writeMetadata + uint64_t bufMinSize = 4; - void RiffVideo::readMetadata() - { - if (io_->open() != 0) throw Error(9, io_->path(), strError()); + //some initial variable declarations and initialization before traversing through chunks + DataBuf chkId(bufMinSize+1); + DataBuf chkSize(bufMinSize+1); - // Ensure that this is the correct image type - if (!isRiffType(*io_, false)) { - if (io_->error() || io_->eof()) throw Error(14); - throw Error(3, "RIFF"); + chkId.pData_[4] = '\0'; + chkSize.pData_[4] = '\0'; + + //skip "RIFF" "chkSize" "AVI" + io_->read(chkId.pData_, bufMinSize); + io_->read(chkSize.pData_, bufMinSize); + io_->read(chkId.pData_, bufMinSize); + + d->m_decodeMetaData = false; + d->m_modifyMetadata = true; + + //write metadata in order + + //find and move to avih position + int32_t dummyLong = 0; + uint64_t i,j,maxCount; + + std::vector strhChunkPositions = findChunkPositions("STRH"); + + std::vector primitiveFlags; + //Add new tags to the beginning of the container prmitiveFlags and handle conditions to the end of case statements. + primitiveFlags.push_back("STRN"); + primitiveFlags.push_back("FMT "); + primitiveFlags.push_back("STRF"); + primitiveFlags.push_back("STRH"); + primitiveFlags.push_back("AVIH"); + + maxCount = (uint64_t) primitiveFlags.size(); + for (j=0; j primitivePositions = findChunkPositions(primitiveFlags.back().c_str()); + primitiveFlags.pop_back(); + for (i=0; i<(uint64_t)primitivePositions.size(); i++){ + io_->seek(primitivePositions[i]+4,BasicIo::beg); + switch (j){ + case 0: aviHeaderTagsHandler(dummyLong); break; + case 1: setStreamType(); + streamHandler(dummyLong); + break; + case 2: io_->seek(strhChunkPositions[i]+4,BasicIo::beg); + setStreamType(); + io_->seek(primitivePositions[i]+4,BasicIo::beg); + streamFormatHandler(dummyLong); + break; + case 3: d->streamType_ = Audio; + streamHandler(dummyLong); + break; + case 4: dateTimeOriginal(dummyLong); break; + default:break; + } } + primitivePositions.clear(); + } - IoCloser closer(*io_); - clearMetadata(); - continueTraversing_ = true; + std::vector headerFlags; + //Add new tags to the beginning of the container headerFlags and handle conditions to the end of case statements. + headerFlags.push_back("INFO"); + headerFlags.push_back("NCDT"); + headerFlags.push_back("ODML"); + headerFlags.push_back("IDIT"); - xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576; - xmpData_["Xmp.video.FileName"] = io_->path(); - xmpData_["Xmp.video.MimeType"] = mimeType(); + maxCount = (uint64_t) headerFlags.size(); + for (j=0; j headerPositions = findHeaderPositions(headerFlags.back().c_str()); + headerFlags.pop_back(); - const long bufMinSize = 4; - DataBuf buf(bufMinSize+1); - buf.pData_[4] = '\0'; + for (i=0; i<(uint64_t)headerPositions.size(); i++){ + io_->seek(headerPositions[i],BasicIo::beg); + switch (j){ + case 0: io_->seek(headerPositions[i]+8,BasicIo::beg); + dateTimeOriginal(dummyLong); + break; + case 1: odmlTagsHandler(); break; + case 2: nikonTagsHandler(); break; + case 3: infoTagsHandler(); break; + //TODO :implement write functionality for header chunks and exif and iptc metadata + default: break; + } + } + headerPositions.clear(); + } + return; +}// RiffVideo::doWriteMetadata +void RiffVideo::readMetadata(){ + if (io_->open() != 0) throw Error(9, io_->path(), strError()); + + // Ensure that this is the correct image type + if (!isRiffType(*io_, false)){ + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "RIFF"); + } + + IoCloser closer(*io_); + clearMetadata(); + + xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576; + xmpData_["Xmp.video.FileName"] = io_->path(); + xmpData_["Xmp.video.MimeType"] = mimeType(); + + DataBuf chkId((const int32_t)5); + DataBuf chkSize((const int32_t)5); + DataBuf chkHeader((const int32_t)5); + + chkId.pData_[4] = '\0'; + chkHeader.pData_[4] = '\0'; + + io_->read(chkId.pData_, 4); + xmpData_["Xmp.video.Container"] = chkId.pData_; + + //skip file size + io_->read(chkSize.pData_, 4); + io_->read(chkHeader.pData_, 4); + xmpData_["Xmp.video.FileType"] = chkHeader.pData_; + + d->m_decodeMetaData = true; + decodeBlock(); + return; +} // RiffVideo::readMetadata + +void RiffVideo::decodeBlock(){ + DataBuf chkId((const int32_t)5); + chkId.pData_[4] = '\0' ; + + io_->read(chkId.pData_, 4); + + if(io_->eof()) return; + else if(UtilsVideo::compareTagValue(chkId, "LIST") || UtilsVideo::compareTagValue(chkId, "JUNK")){ + io_->seek(-4,BasicIo::cur); + tagDecoder(); + } + return; +} // RiffVideo::decodeBlock + +void RiffVideo::tagDecoder(){ + DataBuf chkMainId((const int32_t)5); + chkMainId.pData_[4] = '\0'; + io_->read(chkMainId.pData_, 4); + + if(io_->eof()) return; + + if (UtilsVideo::compareTagValue(chkMainId, "LIST")){ + DataBuf listSize((const int32_t)5); + DataBuf chkHeader((const int32_t)5); + + listSize.pData_[4] = '\0'; + chkHeader.pData_[4] = '\0'; + + io_->read(listSize.pData_, 4); + uint64_t listsize = Exiv2::getULong(listSize.pData_, littleEndian); + io_->read(chkHeader.pData_, 4); + + HeaderChunk* tmpHeaderChunk = new HeaderChunk(); + memcpy((Exiv2::byte* )tmpHeaderChunk->m_headerId,(const Exiv2::byte*)chkHeader.pData_,5); + + int32_t listend = io_->tell() + listsize - 4 ; + + IoPosition position = PremitiveChunk; + while( (position == PremitiveChunk) && (io_->tell() < listend) ){ + DataBuf chkId((const int32_t)5); + DataBuf chkSize((const int32_t)5); + chkId.pData_[4] = '\0'; + chkSize.pData_[4] = '\0'; + + io_->read(chkId.pData_, 4); + io_->read(chkSize.pData_, 4); + + uint64_t size = Exiv2::getULong(chkSize.pData_, littleEndian); + + const char allPrimitiveFlags[][5]={"JUNK","AVIH","FMT ", + "STRH","STRF","STRN","STRD"}; + const char allHeaderFlags[][5]={"NCDT","ODML","MOVI","INFO"}; + + if(UtilsVideo::compareTagValue(chkId,allPrimitiveFlags,(int32_t)(sizeof(allPrimitiveFlags)/5))){ + PrimitiveChunk* tmpPremitiveChunk = new PrimitiveChunk(); + memcpy((Exiv2::byte* )tmpPremitiveChunk->m_chunkId,(const Exiv2::byte*)chkId.pData_,5); + tmpPremitiveChunk->m_chunkLocation = io_->tell() - 8; + tmpPremitiveChunk->m_chunkSize = size; + d->m_riffFileSkeleton.m_primitiveChunks.push_back(tmpPremitiveChunk); + } + + if(UtilsVideo::compareTagValue(chkHeader,allHeaderFlags,(int32_t)(sizeof(allHeaderFlags)/5))){ + tmpHeaderChunk->m_headerLocation = io_->tell() - 16; + tmpHeaderChunk->m_headerSize = listsize ; + d->m_riffFileSkeleton.m_headerChunks.push_back(tmpHeaderChunk); + position = RiffVideo::TraversingChunk; + } + //to handle AVI file formats + if(!d->m_decodeMetaData && UtilsVideo::compareTagValue(chkId,allPrimitiveFlags,(int32_t)(sizeof(allPrimitiveFlags)/5))) io_->seek(size,BasicIo::cur); + + else if(!d->m_decodeMetaData && UtilsVideo::compareTagValue(chkHeader,allHeaderFlags,(int)(sizeof(allHeaderFlags)/5))) io_->seek((listsize - 12),BasicIo::cur); + + else if(UtilsVideo::compareTagValue(chkId, "JUNK")) junkHandler(size); + //primitive chunks note:compare chkId + else if(UtilsVideo::compareTagValue(chkId, "AVIH")) aviHeaderTagsHandler(size); + else if(UtilsVideo::compareTagValue(chkId, "STRH")){ + //since strh and strf exist sequential stream type can be set once + setStreamType(); + streamHandler(size); + } + else if(UtilsVideo::compareTagValue(chkId,"STRF") || UtilsVideo::compareTagValue(chkId, "FMT ")){ + if(UtilsVideo::compareTagValue(chkId,"FMT ")) d->streamType_ = Audio; + streamFormatHandler(size); + } + else if(UtilsVideo::compareTagValue(chkId, "STRN")) dateTimeOriginal(size, 1); + else if(UtilsVideo::compareTagValue(chkId, "STRD")) streamDataTagHandler(size); + //add more else if to support more primitive chunks below if any + //TODO:add indx support + + //recursive call to decode LIST by breaking out of the loop + else if(UtilsVideo::compareTagValue(chkId, "LIST")){ + position = RiffVideo::TraversingChunk; + io_->seek(-8,BasicIo::cur); + } + + //header chunks note:compare chkHeader + else if(UtilsVideo::compareTagValue(chkHeader, "INFO")){ + io_->seek(-16,BasicIo::cur); + infoTagsHandler(); + } + else if(UtilsVideo::compareTagValue(chkHeader, "NCDT")){ + io_->seek(-16,BasicIo::cur); + nikonTagsHandler(); + } + else if(UtilsVideo::compareTagValue(chkHeader, "ODML")){ + io_->seek(-16,BasicIo::cur); + odmlTagsHandler(); + } + //only way to exit from readMetadata() + else if(UtilsVideo::compareTagValue(chkHeader, "MOVI") || UtilsVideo::compareTagValue(chkMainId, "DATA")) io_->seek(listsize-12,BasicIo::cur); + //Add read functionality for custom chunk headers or user created tags here with more (else if) before else. + + //skip block with unknown chunk ID (primitive chunk) + else if(io_->tell() < listend){ + position = RiffVideo::TraversingChunk; + io_->seek((listend - (io_->tell()+4)) ,BasicIo::cur); + } + + //skip chunk with unknown headerId + else io_->seek(io_->tell()+size, BasicIo::cur); + + if(UtilsVideo::compareTagValue(chkId,allPrimitiveFlags,(int32_t)(sizeof(allPrimitiveFlags)/5)) && (size % 2 != 0)) io_->seek(1,BasicIo::cur); + + if(UtilsVideo::compareTagValue(chkId,allHeaderFlags,(int32_t)(sizeof(allHeaderFlags)/5)) && (listsize % 2 != 0)) io_->seek(1,BasicIo::cur); + } + } + + //AVIX can have JUNK chunk directly inside RIFF chunk + else if(UtilsVideo::compareTagValue(chkMainId, "JUNK")){ + DataBuf junkSize((const int32_t)5); + junkSize.pData_[4] = '\0'; + io_->read(junkSize.pData_, 4); + uint64_t size = Exiv2::getULong(junkSize.pData_, littleEndian); + if(!d->m_decodeMetaData){ + HeaderChunk* tmpHeaderChunk = new HeaderChunk(); + tmpHeaderChunk->m_headerLocation = io_->tell() - 8; + tmpHeaderChunk->m_headerSize = size; + d->m_riffFileSkeleton.m_headerChunks.push_back(tmpHeaderChunk); + io_->seek(size,BasicIo::cur); + } + else junkHandler(size); + } + else if(UtilsVideo::compareTagValue(chkMainId, "IDIT")){ + DataBuf dataSize((const int32_t)5); + dataSize.pData_[4] = '\0'; + io_->read(dataSize.pData_, 4); + uint64_t size = Exiv2::getULong(dataSize.pData_, littleEndian); + if(!d->m_decodeMetaData){ + HeaderChunk* tmpHeaderChunk = new HeaderChunk(); + tmpHeaderChunk->m_headerLocation = io_->tell() - 8; + tmpHeaderChunk->m_headerSize = size; + d->m_riffFileSkeleton.m_headerChunks.push_back(tmpHeaderChunk); + io_->seek(size,BasicIo::cur); + } + else dateTimeOriginal(size); + + } + + tagDecoder(); + return; +} // RiffVideo::tagDecoder + +void RiffVideo::streamDataTagHandler(int32_t size){ + const int32_t bufMinSize = 20000; + DataBuf buf(bufMinSize); + buf.pData_[4] = '\0'; + uint64_t cur_pos = io_->tell(); + + io_->read(buf.pData_, 8); + + if(UtilsVideo::compareTagValue(buf, "AVIF")){ + + if (size - 4 < 0){ +#ifndef SUPPRESS_WARNINGS + EXV_ERROR << " Exif Tags found in this RIFF file are not of valid size ." + << " Entries considered invalid. Not Processed.\n"; +#endif + } + else{ + io_->read(buf.pData_, size - 4); + + IptcData iptcData; + XmpData xmpData; + DummyTiffHeader tiffHeader(littleEndian); + TiffParserWorker::decode(exifData_, + iptcData, + xmpData, + buf.pData_, + buf.size_, + Tag::root, + TiffMapping::findDecoder, + &tiffHeader); + +#ifndef SUPPRESS_WARNINGS + if (!iptcData.empty()) EXV_WARNING << "Ignoring IPTC information encoded in the Exif data.\n"; + if (!xmpData.empty()) EXV_WARNING << "Ignoring XMP information encoded in the Exif data.\n"; +#endif + } + } + // TODO decode CasioData and ZORA Tag + io_->seek(cur_pos + size, BasicIo::beg); + return; +} // RiffVideo::streamDataTagHandler + +void RiffVideo::dateTimeOriginal(int32_t size, int32_t i){ + uint64_t cur_pos = io_->tell(); + if(!d->m_modifyMetadata){ + io_->seek(-4,BasicIo::cur); + DataBuf dataLength(2); + dataLength.pData_[1] = '\0'; + + io_->read(dataLength.pData_,1); + uint64_t bufMinSize = (uint64_t)Exiv2::getShort(dataLength.pData_, littleEndian); + DataBuf buf((uint64_t)bufMinSize); + io_->seek(3,BasicIo::cur); io_->read(buf.pData_, bufMinSize); - xmpData_["Xmp.video.Container"] = buf.pData_; - io_->read(buf.pData_, bufMinSize); - io_->read(buf.pData_, bufMinSize); - xmpData_["Xmp.video.FileType"] = buf.pData_; - - while (continueTraversing_) decodeBlock(); - } // RiffVideo::readMetadata - - void RiffVideo::decodeBlock() - { - const long bufMinSize = 4; - DataBuf buf(bufMinSize+1); - DataBuf buf2(bufMinSize+1); - unsigned long size = 0; - buf.pData_[4] = '\0' ; - buf2.pData_[4] = '\0' ; - - io_->read(buf2.pData_, 4); - - if(io_->eof() || equalsRiffTag(buf2, "MOVI") || equalsRiffTag(buf2, "DATA")) { - continueTraversing_ = false; - return; - } - else if(equalsRiffTag(buf2, "HDRL") || equalsRiffTag(buf2, "STRL")) { - decodeBlock(); - } - else { - io_->read(buf.pData_, 4); - size = Exiv2::getULong(buf.pData_, littleEndian); - - tagDecoder(buf2, size); - } - } // RiffVideo::decodeBlock - - void RiffVideo::tagDecoder(Exiv2::DataBuf& buf, unsigned long size) - { - uint64_t cur_pos = io_->tell(); - static bool listFlag = false, listEnd = false; - - if(equalsRiffTag(buf, "LIST")) { - listFlag = true; - listEnd = false; - - while((uint64_t)(io_->tell()) < cur_pos + size) decodeBlock(); - - listEnd = true; - io_->seek(cur_pos + size, BasicIo::beg); - } - else if(equalsRiffTag(buf, "JUNK") && listEnd) { - junkHandler(size); - } - else if(equalsRiffTag(buf, "AVIH")) { - listFlag = false; - aviHeaderTagsHandler(size); - } - else if(equalsRiffTag(buf, "STRH")) { - listFlag = false; - streamHandler(size); - } - else if(equalsRiffTag(buf,"STRF") || equalsRiffTag(buf, "FMT ")) { - listFlag = false; - if(equalsRiffTag(buf,"FMT ")) - streamType_ = Audio; - streamFormatHandler(size); - } - else if(equalsRiffTag(buf, "STRN")) { - listFlag = false; - dateTimeOriginal(size, 1); - } - else if(equalsRiffTag(buf, "STRD")) { - listFlag = false; - streamDataTagHandler(size); - } - else if(equalsRiffTag(buf, "IDIT")) { - listFlag = false; - dateTimeOriginal(size); - } - else if(equalsRiffTag(buf, "INFO")) { - listFlag = false; - infoTagsHandler(); - } - else if(equalsRiffTag(buf, "NCDT")) { - listFlag = false; - nikonTagsHandler(); - } - else if(equalsRiffTag(buf, "ODML")) { - listFlag = false; - odmlTagsHandler(); - } - else if (listFlag) { - // std::cout<<"|unprocessed|"<seek(cur_pos + size, BasicIo::beg); - } - } // RiffVideo::tagDecoder - - void RiffVideo::streamDataTagHandler(long size) - { - const long bufMinSize = 20000; - DataBuf buf(bufMinSize); - buf.pData_[4] = '\0'; - uint64_t cur_pos = io_->tell(); - - io_->read(buf.pData_, 8); - - if(equalsRiffTag(buf, "AVIF")) { - - if (size - 4 < 0) { - #ifndef SUPPRESS_WARNINGS - EXV_ERROR << " Exif Tags found in this RIFF file are not of valid size ." - << " Entries considered invalid. Not Processed.\n"; - #endif - } - else { - io_->read(buf.pData_, size - 4); - - IptcData iptcData; - XmpData xmpData; - DummyTiffHeader tiffHeader(littleEndian); - TiffParserWorker::decode(exifData_, - iptcData, - xmpData, - buf.pData_, - buf.size_, - Tag::root, - TiffMapping::findDecoder, - &tiffHeader); - - #ifndef SUPPRESS_WARNINGS - if (!iptcData.empty()) { - EXV_WARNING << "Ignoring IPTC information encoded in the Exif data.\n"; - } - if (!xmpData.empty()) { - EXV_WARNING << "Ignoring XMP information encoded in the Exif data.\n"; - } - #endif - } - } - // TODO decode CasioData and ZORA Tag + if(!i) xmpData_["Xmp.video.DateUT"] = buf.pData_; + else xmpData_["Xmp.video.StreamName"] = buf.pData_; io_->seek(cur_pos + size, BasicIo::beg); + } + else{ + DataBuf dataLength(2); + dataLength.pData_[1] = '\0'; + io_->read(dataLength.pData_,1); + io_->seek(3,BasicIo::cur); + int32_t bufMinSize = (uint64_t)Exiv2::getShort(dataLength.pData_, littleEndian); - } // RiffVideo::streamDataTagHandler - - void RiffVideo::dateTimeOriginal(long size, int i) - { - uint64_t cur_pos = io_->tell(); - const long bufMinSize = 100; - DataBuf buf(bufMinSize); - io_->read(buf.pData_, size); - if(!i) - xmpData_["Xmp.video.DateUTC"] = buf.pData_; - else - xmpData_["Xmp.video.StreamName"] = buf.pData_; + if(xmpData_["Xmp.video.DateUT"].count() > 0) writeStringData(xmpData_["Xmp.video.DateUT"],bufMinSize); + else if(xmpData_["Xmp.video.StreamName"].count() >0) writeStringData(xmpData_["Xmp.video.StreamName"],bufMinSize); io_->seek(cur_pos + size, BasicIo::beg); - } // RiffVideo::dateTimeOriginal + } + return; +} // RiffVideo::dateTimeOriginal - void RiffVideo::odmlTagsHandler() - { - const long bufMinSize = 100; - DataBuf buf(bufMinSize); - buf.pData_[4] = '\0'; - io_->seek(-12, BasicIo::cur); - io_->read(buf.pData_, 4); - unsigned long size = Exiv2::getULong(buf.pData_, littleEndian); - unsigned long size2 = size; +void RiffVideo::odmlTagsHandler(){ + const int32_t bufMinSize = 4; + DataBuf buf(bufMinSize + 1); + buf.pData_[4] = '\0'; + io_->read(buf.pData_,4); + + if(!d->m_modifyMetadata){ + uint64_t size = Exiv2::getULong(buf.pData_, littleEndian); + uint64_t size2 = size; uint64_t cur_pos = io_->tell(); io_->read(buf.pData_, 4); size -= 4; - while(size > 0) { + while(size > 0){ io_->read(buf.pData_, 4); size -= 4; - if(equalsRiffTag(buf,"DMLH")) { + if(UtilsVideo::compareTagValue(buf,"DMLH")){ io_->read(buf.pData_, 4); size -= 4; io_->read(buf.pData_, 4); size -= 4; xmpData_["Xmp.video.TotalFrameCount"] = Exiv2::getULong(buf.pData_, littleEndian); } } io_->seek(cur_pos + size2, BasicIo::beg); - } // RiffVideo::odmlTagsHandler + } + else{ + if(xmpData_["Xmp.video.TotalFrameCount"].count() > 0){ + uint64_t tmpSize = Exiv2::getULong(buf.pData_, littleEndian); + while(tmpSize > 0){ + io_->read(buf.pData_,4); tmpSize -= 4; + if(UtilsVideo::compareTagValue(buf,"DMLH")){ + io_->seek(4,BasicIo::cur); + writeLongData(xmpData_["Xmp.video.TotalFrameCount"]); + return; + } + } + } + } + return; +} // RiffVideo::odmlTagsHandler - void RiffVideo::skipListData() - { - const long bufMinSize = 4; - DataBuf buf(bufMinSize+1); - buf.pData_[4] = '\0'; - io_->seek(-12, BasicIo::cur); +void RiffVideo::skipListData(){ + const int32_t bufMinSize = 4; + DataBuf buf(bufMinSize+1); + buf.pData_[4] = '\0'; + io_->seek(-12, BasicIo::cur); + io_->read(buf.pData_, 4); + uint64_t size = Exiv2::getULong(buf.pData_, littleEndian); + + uint64_t cur_pos = io_->tell(); + io_->seek(cur_pos + size, BasicIo::beg); + return; +} // RiffVideo::skipListData + +void RiffVideo::nikonTagsHandler(){ + const int32_t bufMinSize = 100; + DataBuf buf(bufMinSize), buf2(4+1); + buf.pData_[4] = '\0'; + io_->read(buf.pData_, 4); + + int32_t internal_size = 0, tagID = 0, dataSize = 0, tempSize, size = Exiv2::getULong(buf.pData_, littleEndian); + tempSize = size; char str[9] = " . . . "; + uint64_t internal_pos, cur_pos; internal_pos = cur_pos = io_->tell(); + + const TagDetails* td; + double denominator = 1; + io_->read(buf.pData_, 4); tempSize -= 4; + + while((int32_t)tempSize > 0){ + std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 4); - unsigned long size = Exiv2::getULong(buf.pData_, littleEndian); + io_->read(buf2.pData_, 4); + int32_t temp = internal_size = Exiv2::getULong(buf2.pData_, littleEndian); + internal_pos = io_->tell(); tempSize -= (internal_size + 8); - uint64_t cur_pos = io_->tell(); - io_->seek(cur_pos + size, BasicIo::beg); - } // RiffVideo::skipListData + if(UtilsVideo::compareTagValue(buf, "NCVR")){ + while((int32_t)temp > 3){ + std::memset(buf.pData_, 0x0, buf.size_); + io_->read(buf.pData_, 2); + tagID = Exiv2::getULong(buf.pData_, littleEndian); + io_->read(buf.pData_, 2); + dataSize = Exiv2::getULong(buf.pData_, littleEndian); + temp -= (4 + dataSize); - void RiffVideo::nikonTagsHandler() - { - const long bufMinSize = 100; - DataBuf buf(bufMinSize), buf2(4+1); - buf.pData_[4] = '\0'; - io_->seek(-12, BasicIo::cur); - io_->read(buf.pData_, 4); - - long internal_size = 0, tagID = 0, dataSize = 0, tempSize, size = Exiv2::getULong(buf.pData_, littleEndian); - tempSize = size; char str[9] = " . . . "; - uint64_t internal_pos, cur_pos; internal_pos = cur_pos = io_->tell(); - const TagDetails* td; - double denominator = 1; - io_->read(buf.pData_, 4); tempSize -= 4; - - while((long)tempSize > 0) { - std::memset(buf.pData_, 0x0, buf.size_); - io_->read(buf.pData_, 4); - io_->read(buf2.pData_, 4); - int temp = internal_size = Exiv2::getULong(buf2.pData_, littleEndian); - internal_pos = io_->tell(); tempSize -= (internal_size + 8); - - if(equalsRiffTag(buf, "NCVR")) { - while((long)temp > 3) { - std::memset(buf.pData_, 0x0, buf.size_); - io_->read(buf.pData_, 2); - tagID = Exiv2::getULong(buf.pData_, littleEndian); - io_->read(buf.pData_, 2); - dataSize = Exiv2::getULong(buf.pData_, littleEndian); - temp -= (4 + dataSize); - - if(tagID == 0x0001) { - if (dataSize <= 0) { - #ifndef SUPPRESS_WARNINGS - EXV_ERROR << " Makernotes found in this RIFF file are not of valid size ." - << " Entries considered invalid. Not Processed.\n"; - #endif - } - else { + if(tagID == 0x0001){ + if (dataSize <= 0){ +#ifndef SUPPRESS_WARNINGS + EXV_ERROR << " Makernotes found in this RIFF file are not of valid size ." + << " Entries considered invalid. Not Processed.\n"; +#endif + } + else if(!d->m_modifyMetadata){ io_->read(buf.pData_, dataSize); xmpData_["Xmp.video.MakerNoteType"] = buf.pData_; - } } - else if (tagID == 0x0002) { - while(dataSize) { + else writeStringData(xmpData_["Xmp.video.MakerNoteType"],dataSize); + } + else if (tagID == 0x0002){ + if (dataSize <= 0){ + } + else if(!d->m_modifyMetadata){ + while(dataSize){ std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 1); str[(4 - dataSize) * 2] = (char)(Exiv2::getULong(buf.pData_, littleEndian) + 48); --dataSize; } xmpData_["Xmp.video.MakerNoteVersion"] = str; } + //this is necessary block + else if(xmpData_["Xmp.video.MakerNoteVersion"].count() > 0){ + int32_t originalDataSize = dataSize; + std::string makerNoteVersion = xmpData_["Xmp.video.MakerNoteVersion"].toString(); + Exiv2::byte* rawMakerNoteVersion = new byte[originalDataSize]; + int32_t tmpCounter = 0; + int32_t i; + for(i=(int32_t)min((int32_t)dataSize,(int32_t)makerNoteVersion.size()); + i>=(int32_t)0; i--){ + rawMakerNoteVersion[tmpCounter] = (Exiv2::byte) (makerNoteVersion[(4 - i) * 2] - 48); + tmpCounter++; + } + if((int32_t)originalDataSize > (int32_t)makerNoteVersion.size()){ + for(i=(int32_t)(makerNoteVersion.size()); iwrite(rawMakerNoteVersion,originalDataSize); + delete[] rawMakerNoteVersion; + } + else io_->seek(dataSize,BasicIo::cur); } } - else if(equalsRiffTag(buf, "NCTG")) { - while((long)temp > 3) { + } + else if(UtilsVideo::compareTagValue(buf, "NCTG")){ + if(!d->m_modifyMetadata){ + while((int32_t)temp > 3){ std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 2); tagID = Exiv2::getULong(buf.pData_, littleEndian); @@ -800,119 +1094,205 @@ namespace Exiv2 { temp -= (4 + dataSize); td = find(nikonAVITags , tagID); - if (dataSize <= 0) { - #ifndef SUPPRESS_WARNINGS - EXV_ERROR << " Makernotes found in this RIFF file are not of valid size ." - << " Entries considered invalid. Not Processed.\n"; - #endif + if (dataSize <= 0){ } - else { - io_->read(buf.pData_, dataSize); + else{ + switch (tagID) + { + case 0x0003: case 0x0004: case 0x0005: case 0x0006: + case 0x0013: case 0x0014: case 0x0018: case 0x001d: + case 0x001e: case 0x001f: case 0x0020: + io_->read(buf.pData_, dataSize); + xmpData_[exvGettext(td->label_)] = buf.pData_; + break; + case 0x0007: case 0x0010: case 0x0011: case 0x000c: + case 0x0012: + io_->read(buf.pData_, dataSize); + xmpData_[exvGettext(td->label_)] = Exiv2::getULong(buf.pData_, littleEndian); + break; + case 0x0008: case 0x0009: case 0x000a: case 0x000b: + case 0x000f: case 0x001b: case 0x0016: - switch (tagID) { - case 0x0003: case 0x0004: case 0x0005: case 0x0006: - case 0x0013: case 0x0014: case 0x0018: case 0x001d: - case 0x001e: case 0x001f: case 0x0020: - xmpData_[exvGettext(td->label_)] = buf.pData_; break; + io_->read(buf.pData_, dataSize); + buf2.pData_[0] = buf.pData_[4]; + buf2.pData_[1] = buf.pData_[5]; + buf2.pData_[2] = buf.pData_[6]; + buf2.pData_[3] = buf.pData_[7]; + denominator = (double)Exiv2::getLong(buf2.pData_, littleEndian); - case 0x0007: case 0x0010: case 0x0011: case 0x000c: - case 0x0012: - xmpData_[exvGettext(td->label_)] = Exiv2::getULong(buf.pData_, littleEndian); break; + if (denominator != 0) xmpData_[exvGettext(td->label_)] = (double)Exiv2::getLong(buf.pData_, littleEndian) / denominator; + else xmpData_[exvGettext(td->label_)] = 0; + break; - case 0x0008: case 0x0009: case 0x000a: case 0x000b: - case 0x000f: case 0x001b: case 0x0016: - buf2.pData_[0] = buf.pData_[4]; buf2.pData_[1] = buf.pData_[5]; - buf2.pData_[2] = buf.pData_[6]; buf2.pData_[3] = buf.pData_[7]; - denominator = (double)Exiv2::getLong(buf2.pData_, littleEndian); - if (denominator != 0) - xmpData_[exvGettext(td->label_)] = (double)Exiv2::getLong(buf.pData_, littleEndian) / denominator; - else - xmpData_[exvGettext(td->label_)] = 0; - break; - - default: - break; + default: io_->read(buf.pData_, dataSize); + break; + } } + } + } + else{ + while((int32_t)temp > 3){ + std::memset(buf.pData_, 0x0, buf.size_); + io_->read(buf.pData_, 2); + tagID = Exiv2::getULong(buf.pData_, littleEndian); + io_->read(buf.pData_, 2); + dataSize = Exiv2::getULong(buf.pData_, littleEndian); + temp -= (4 + dataSize); + td = find(nikonAVITags , tagID); + + if (dataSize <= 0){ + } + else{ + switch (tagID){ + case 0x0003: case 0x0004: case 0x0005: case 0x0006: + case 0x0013: case 0x0014: case 0x0018: case 0x001d: + case 0x001e: case 0x001f: case 0x0020: + writeStringData(xmpData_[exvGettext(td->label_)],dataSize); + break; + case 0x0007: case 0x0010: case 0x0011: case 0x000c: + case 0x0012: + writeLongData(xmpData_[exvGettext(td->label_)],dataSize); + break; + case 0x0008: case 0x0009: case 0x000a: case 0x000b: + case 0x000f: case 0x001b: case 0x0016: + + io_->read(buf.pData_, dataSize); + buf2.pData_[0] = buf.pData_[4]; + buf2.pData_[1] = buf.pData_[5]; + buf2.pData_[2] = buf.pData_[6]; + buf2.pData_[3] = buf.pData_[7]; + denominator = (double)Exiv2::getLong(buf2.pData_, littleEndian); + + //Variation + if(xmpData_[exvGettext(td->label_)].count() > 0){ + io_->seek(-dataSize,BasicIo::cur); + int32_t nikonData = (int32_t)(xmpData_[exvGettext(td->label_)].toFloat()*denominator); + io_->write((Exiv2::byte*)&nikonData,4); + io_->seek((dataSize-4),BasicIo::cur); + } + else io_->seek(dataSize,BasicIo::cur); + break; + + default: io_->read(buf.pData_, dataSize); + break; + } } } } - else if(equalsRiffTag(buf, "NCTH")) {//TODO Nikon Thumbnail Image + } + + else if(UtilsVideo::compareTagValue(buf, "NCTH")){//TODO Nikon Thumbnail Image + } + + else if(UtilsVideo::compareTagValue(buf, "NCVW")){//TODO Nikon Preview Image + } + + io_->seek(internal_pos + internal_size, BasicIo::beg); + } + + if (size ==0) io_->seek(cur_pos + 4, BasicIo::beg); + else io_->seek(cur_pos + size, BasicIo::beg); + return; +} // RiffVideo::nikonTagsHandler + +void RiffVideo::infoTagsHandler(){ + const int32_t bufMinSize = 4; + DataBuf buf(bufMinSize + 1); + buf.pData_[4] = '\0'; + const int32_t cur_pos = io_->tell(); + io_->read(buf.pData_, 4); + int32_t size = Exiv2::getULong(buf.pData_, littleEndian); + io_->seek(4,BasicIo::cur); + + int32_t dataLenght = size; + const TagVocabulary* tv; + + int32_t infoSize; + if(!d->m_modifyMetadata){ + const char allPrimitiveFlags[][5]={"GENR","DIRC","IART","ICNM","IEDT","IENG","ILNG", + "IMUS","INAM","IPRO","ISRC","ISTR","LANG","LOCA", + "TAPE","YEAR","IPRD","IKEY","ICOP","ICNT","CMNT"}; + while(dataLenght > 12){ + io_->read(buf.pData_, 4); + if(UtilsVideo::compareTagValue(buf,allPrimitiveFlags,(int32_t)(sizeof(allPrimitiveFlags)/5))){ + PrimitiveChunk* tmpPremitiveChunk = new PrimitiveChunk(); + memcpy((Exiv2::byte*)tmpPremitiveChunk->m_chunkId,(const Exiv2::byte*)buf.pData_,5); + tmpPremitiveChunk->m_chunkLocation = io_->tell() - 4; + d->m_riffFileSkeleton.m_primitiveChunks.push_back(tmpPremitiveChunk); } - else if(equalsRiffTag(buf, "NCVW")) {//TODO Nikon Preview Image - } - - io_->seek(internal_pos + internal_size, BasicIo::beg); - } - - if (size ==0) { - io_->seek(cur_pos + 4, BasicIo::beg); - } - else { - io_->seek(cur_pos + size, BasicIo::beg); - } - } // RiffVideo::nikonTagsHandler - - void RiffVideo::infoTagsHandler() - { - const long bufMinSize = 10000; - DataBuf buf(bufMinSize); - buf.pData_[4] = '\0'; - io_->seek(-12, BasicIo::cur); - io_->read(buf.pData_, 4); - long infoSize, size = Exiv2::getULong(buf.pData_, littleEndian); - long size_external = size; - const TagVocabulary* tv; - - uint64_t cur_pos = io_->tell(); - io_->read(buf.pData_, 4); size -= 4; - - while(size > 3) { - io_->read(buf.pData_, 4); size -= 4; - if(!Exiv2::getULong(buf.pData_, littleEndian)) - break; - tv = find(infoTags , Exiv2::toString( buf.pData_)); - io_->read(buf.pData_, 4); size -= 4; + tv = find(infoTags , Exiv2::toString(buf.pData_)); + io_->read(buf.pData_, 4); infoSize = Exiv2::getULong(buf.pData_, littleEndian); - - if(infoSize >= 0) { - size -= infoSize; - io_->read(buf.pData_, infoSize); - if(infoSize < 4) - buf.pData_[infoSize] = '\0'; + dataLenght -= infoSize; + if(tv && infoSize > 4){ + DataBuf tmpBuf((uint64_t)infoSize+1); + tmpBuf.pData_[infoSize] = '\0'; + io_->read(tmpBuf.pData_,infoSize); + xmpData_[exvGettext(tv->label_)] = tmpBuf.pData_; } - - if(tv) - xmpData_[exvGettext(tv->label_)] = buf.pData_; - else - continue; } - io_->seek(cur_pos + size_external, BasicIo::beg); - } // RiffVideo::infoTagsHandler + io_->seek(cur_pos + size, BasicIo::beg); + } + else{ + //First write the tags which already exist in a file + std::vector existingInfoTags; + while(dataLenght > 0){ + io_->read(buf.pData_, 4); + tv = find(infoTags , Exiv2::toString( buf.pData_)); + io_->read(buf.pData_, 4); + infoSize = Exiv2::getULong(buf.pData_, littleEndian); + dataLenght -= infoSize; - void RiffVideo::junkHandler(long size) - { - const long bufMinSize = size; - - if (size < 0) { - #ifndef SUPPRESS_WARNINGS - EXV_ERROR << " Junk Data found in this RIFF file are not of valid size ." - << " Entries considered invalid. Not Processed.\n"; - #endif - io_->seek(io_->tell() + 4, BasicIo::beg); + if(tv){ + if(xmpData_[exvGettext(tv->label_)].count() >0){ + existingInfoTags.push_back((std::string)tv->voc_); + writeStringData(xmpData_[exvGettext(tv->label_)],infoSize); + } + } } - else { + //Secondly write tags which are supported by Digikam, + //Note that create new LIST chunk is created if tag did not exist before + std::vector > writethis; + for(int32_t i =0; i< (int32_t)(sizeof(infoTags)/sizeof(infoTags[0])); i++){ + const std::string infoTagData = xmpData_[infoTags[i].label_].toString(); + const std::string infoTagFlag = (std::string)infoTags[i].voc_; + if((xmpData_[infoTags[i].label_].count() > 0) && + ((findChunkPositions(infoTags[i].voc_)).size() == 0) + && !(std::find(existingInfoTags.begin(), existingInfoTags.end(), infoTagFlag) != existingInfoTags.end())) + writethis.push_back(make_pair(infoTagData,infoTagFlag)); + } + + if(writethis.size() > 0){ + io_->seek(cur_pos, BasicIo::beg); + writeNewSubChunks(writethis); + } + + io_->seek(cur_pos + size, BasicIo::beg); + } + return; +} // RiffVideo::infoTagsHandler + +void RiffVideo::junkHandler(int32_t size){ + const int32_t bufMinSize = size; + + if (size < 0){ +#ifndef SUPPRESS_WARNINGS + EXV_ERROR << " Junk Data found in this RIFF file are not of valid size ." + << " Entries considered invalid. Not Processed.\n"; +#endif + io_->seek(io_->tell() + 4, BasicIo::beg); + } + + else{ DataBuf buf(bufMinSize+1), buf2(4+1); - std::memset(buf.pData_, 0x0, buf.size_); - buf2.pData_[4] = '\0'; uint64_t cur_pos = io_->tell(); io_->read(buf.pData_, 4); //! Pentax Metadata and Tags - if(equalsRiffTag(buf, "PENT")) { - + if(UtilsVideo::compareTagValue(buf, "PENT")){ io_->seek(cur_pos + 18, BasicIo::beg); io_->read(buf.pData_, 26); xmpData_["Xmp.video.Make"] = buf.pData_; @@ -961,53 +1341,44 @@ namespace Exiv2 { xmpData_.add(Exiv2::XmpKey("Xmp.xmp.Thumbnails/xmpGImg:image"), &tv); */ } - else { + else{ io_->seek(cur_pos, BasicIo::beg); io_->read(buf.pData_, size); xmpData_["Xmp.video.Junk"] = buf.pData_; } io_->seek(cur_pos + size, BasicIo::beg); - } - } // RiffVideo::junkHandler + } + return; +} // RiffVideo::junkHandler - void RiffVideo::aviHeaderTagsHandler(long size) - { - const long bufMinSize = 4; +void RiffVideo::aviHeaderTagsHandler(int32_t size){ + if(!d->m_modifyMetadata){ + const int32_t bufMinSize = 4; DataBuf buf(bufMinSize+1); buf.pData_[4] = '\0'; - long width = 0, height = 0, frame_count = 0; + int32_t width = 0, height = 0, frame_count = 0; double frame_rate = 1; - uint64_t cur_pos = io_->tell(); + uint64_t cur_pos = io_->tell(),i; - for(int i = 0; i <= 9; i++) { + for( i = 0; i <= 9; i++){ std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, bufMinSize); - switch(i) { - case frameRate: - xmpData_["Xmp.video.MicroSecPerFrame"] = Exiv2::getULong(buf.pData_, littleEndian); - frame_rate = (double)1000000/(double)Exiv2::getULong(buf.pData_, littleEndian); - break; - case (maxDataRate): - xmpData_["Xmp.video.MaxDataRate"] = (double)Exiv2::getULong(buf.pData_, littleEndian)/(double)1024; - break; - case frameCount: - xmpData_["Xmp.video.FrameCount"] = Exiv2::getULong(buf.pData_, littleEndian); - frame_count = Exiv2::getULong(buf.pData_, littleEndian); - break; - case streamCount: - xmpData_["Xmp.video.StreamCount"] = Exiv2::getULong(buf.pData_, littleEndian); - break; - case imageWidth_h: - width = Exiv2::getULong(buf.pData_, littleEndian); - xmpData_["Xmp.video.Width"] = width; - break; - case imageHeight_h: - height = Exiv2::getULong(buf.pData_, littleEndian); - xmpData_["Xmp.video.Height"] = height; - break; + switch(i){ + case frameRate: xmpData_["Xmp.video.MicroSecPerFrame"] = Exiv2::getULong(buf.pData_, littleEndian); + frame_rate = (double)1000000/(double)Exiv2::getULong(buf.pData_, littleEndian); break; + case (maxDataRate): xmpData_["Xmp.video.MaxDataRate"] = (double)Exiv2::getULong(buf.pData_, littleEndian)/(double)1024; break; + case frameCount: xmpData_["Xmp.video.FrameCount"] = Exiv2::getULong(buf.pData_, littleEndian); + frame_count = Exiv2::getULong(buf.pData_, littleEndian); break; + case initialFrames: xmpData_["Xmp.video.InitialFrames"] = Exiv2::getULong(buf.pData_, littleEndian); break; + case streamCount: xmpData_["Xmp.video.StreamCount"] = Exiv2::getULong(buf.pData_, littleEndian); break; + case suggestedBufferSize: xmpData_["Xmp.video.SuggestedBufferSize"] = Exiv2::getULong(buf.pData_, littleEndian); break; + case imageWidth_h: width = Exiv2::getULong(buf.pData_, littleEndian); + xmpData_["Xmp.video.Width"] = width; break; + case imageHeight_h: height = Exiv2::getULong(buf.pData_, littleEndian); + xmpData_["Xmp.video.Height"] = height; break; } } @@ -1015,237 +1386,502 @@ namespace Exiv2 { fillDuration(frame_rate, frame_count); io_->seek(cur_pos + size, BasicIo::beg); - } // RiffVideo::aviHeaderTagsHandler + } + else//overwrite metadata from current xmpData_ container{ + for(int32_t i = 0; i <= 9; i++){ + switch(i){ + case frameRate: writeLongData(xmpData_["Xmp.video.MicroSecPerFrame"]); break; + case (maxDataRate): if(xmpData_["Xmp.video.MaxDataRate"].count() > 0 ){ + int32_t maxDataRate = (int32_t)(xmpData_["Xmp.video.MaxDataRate"].toFloat()*1024); + io_->write((Exiv2::byte*)&maxDataRate,4); + } + else io_->seek(4,BasicIo::cur); + break; + case frameCount: writeLongData(xmpData_["Xmp.video.FrameCount"]); break; + case initialFrames: writeLongData(xmpData_["Xmp.video.InitialFrames"]); break; + case streamCount: writeLongData(xmpData_["Xmp.video.StreamCount"]); break; + case suggestedBufferSize: writeLongData(xmpData_["Xmp.video.SuggestedBufferSize"]); break; + case imageWidth_h: writeLongData(xmpData_["Xmp.video.Width"]); break; + case imageHeight_h: writeLongData(xmpData_["Xmp.video.Height"]); break; + default: io_->seek(4,BasicIo::cur); break; + } + } + return; +} // RiffVideo::aviHeaderTagsHandler - void RiffVideo::streamHandler(long size) - { - const long bufMinSize = 4; +void RiffVideo::setStreamType(){ + DataBuf chkId((uint64_t)5); + io_->read(chkId.pData_,(uint64_t)4); + if(UtilsVideo::compareTagValue(chkId, "VIDS")) + d->streamType_ = Video; + else if (UtilsVideo::compareTagValue(chkId, "AUDS")) + d->streamType_ = Audio; + return; +}//RiffVideo::setStreamType + +void RiffVideo::streamHandler(int32_t size){ + if (!d->m_modifyMetadata){ + uint64_t bufMinSize = 4; DataBuf buf(bufMinSize+1); - buf.pData_[4]='\0'; - long divisor = 1; - uint64_t cur_pos = io_->tell(); + buf.pData_[4] = '\0'; + int32_t divisor = 1; + uint64_t cur_pos = io_->tell() - 4; - io_->read(buf.pData_, bufMinSize); - if(equalsRiffTag(buf, "VIDS")) - streamType_ = Video; - else if (equalsRiffTag(buf, "AUDS")) - streamType_ = Audio; - - for(int i=1; i<=25; i++) { + int32_t i; + for( i=1; i<=25; i++){ std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, bufMinSize); - switch(i) { + switch(i){ case codec: - if(streamType_ == Video) - xmpData_["Xmp.video.Codec"] = buf.pData_; - else if (streamType_ == Audio) - xmpData_["Xmp.audio.Codec"] = buf.pData_; - else - xmpData_["Xmp.video.Codec"] = buf.pData_; + if(d->streamType_ == Video) xmpData_["Xmp.video.Codec"] = buf.pData_; + else if (d->streamType_ == Audio) xmpData_["Xmp.audio.Codec"] = buf.pData_; + else xmpData_["Xmp.video.Codec"] = buf.pData_; break; - case sampleRate: - divisor=Exiv2::getULong(buf.pData_, littleEndian); + case sampleRate: divisor=Exiv2::getULong(buf.pData_, littleEndian); break; + case (sampleRate+1): if(d->streamType_ == Video) xmpData_["Xmp.video.FrameRate"] = returnSampleRate(buf,divisor); + else if (d->streamType_ == Audio) xmpData_["Xmp.audio.SampleRate"] = returnSampleRate(buf,divisor); + else xmpData_["Xmp.video.StreamSampleRate"] = returnSampleRate(buf,divisor); break; - case (sampleRate+1): - if(streamType_ == Video) - xmpData_["Xmp.video.FrameRate"] = returnSampleRate(buf,divisor); - else if (streamType_ == Audio) - xmpData_["Xmp.audio.SampleRate"] = returnSampleRate(buf,divisor); - else - xmpData_["Xmp.video.StreamSampleRate"] = returnSampleRate(buf,divisor); + case sampleCount: if(d->streamType_ == Video) xmpData_["Xmp.video.FrameCount"] = Exiv2::getULong(buf.pData_, littleEndian); + else if (d->streamType_ == Audio) xmpData_["Xmp.audio.SampleCount"] = Exiv2::getULong(buf.pData_, littleEndian); + else xmpData_["Xmp.video.StreamSampleCount"] = Exiv2::getULong(buf.pData_, littleEndian); break; - case sampleCount: - if(streamType_ == Video) - xmpData_["Xmp.video.FrameCount"] = Exiv2::getULong(buf.pData_, littleEndian); - else if (streamType_ == Audio) - xmpData_["Xmp.audio.SampleCount"] = Exiv2::getULong(buf.pData_, littleEndian); - else - xmpData_["Xmp.video.StreamSampleCount"] = Exiv2::getULong(buf.pData_, littleEndian); + case quality: if(d->streamType_ == Video) xmpData_["Xmp.video.VideoQuality"] = Exiv2::getULong(buf.pData_, littleEndian); + else if(d->streamType_ != Audio) xmpData_["Xmp.video.StreamQuality"] = Exiv2::getULong(buf.pData_, littleEndian); break; - case quality: - if(streamType_ == Video) - xmpData_["Xmp.video.VideoQuality"] = Exiv2::getULong(buf.pData_, littleEndian); - else if(streamType_ != Audio) - xmpData_["Xmp.video.StreamQuality"] = Exiv2::getULong(buf.pData_, littleEndian); - break; - case sampleSize: - if(streamType_ == Video) - xmpData_["Xmp.video.VideoSampleSize"] = Exiv2::getULong(buf.pData_, littleEndian); - else if(streamType_ != Audio) - xmpData_["Xmp.video.StreamSampleSize"] = Exiv2::getULong(buf.pData_, littleEndian); + case sampleSize: if(d->streamType_ == Video) xmpData_["Xmp.video.VideoSampleSize"] = Exiv2::getULong(buf.pData_, littleEndian); + else if(d->streamType_ != Audio) xmpData_["Xmp.video.StreamSampleSize"] = Exiv2::getULong(buf.pData_, littleEndian); break; } } io_->seek(cur_pos + size, BasicIo::beg); - } // RiffVideo::streamHandler + } + else{ + DataBuf chkId((uint64_t)5); + chkId.pData_[4] = '\0'; + const int32_t bufMinSize = 4; - void RiffVideo::streamFormatHandler(long size) - { - const long bufMinSize = 4; + int32_t multiplier; + if(d->streamType_ == Video){ + writeStringData(xmpData_["Xmp.video.Codec"],4,12); + io_->read(chkId.pData_,bufMinSize); + multiplier = Exiv2::getULong(chkId.pData_, littleEndian); + + //Variation + if(xmpData_["Xmp.video.FrameRate"].count() > 0){ + int32_t frameRate = (int32_t)xmpData_["Xmp.video.FrameRate"].toFloat()*multiplier; + io_->write((Exiv2::byte*)&frameRate,4); + io_->seek(4,BasicIo::cur); + } + else io_->seek(8,BasicIo::cur); + + writeLongData(xmpData_["Xmp.video.FrameCount"],4,4); + writeLongData(xmpData_["Xmp.video.VideoQuality"],4); + writeLongData(xmpData_["Xmp.video.VideoSampleSize"],4); + } + else if(d->streamType_ == Audio){ + writeStringData(xmpData_["Xmp.audio.Codec"],4,12); + + io_->read(chkId.pData_,bufMinSize); + multiplier = Exiv2::getULong(chkId.pData_, littleEndian); + + //Variation + if(xmpData_["Xmp.audio.SampleRate"].count() > 0){ + int32_t sampleRate = (int32_t)xmpData_["Xmp.audio.SampleRate"].toLong()*multiplier; + io_->write((Exiv2::byte*)&sampleRate,4); + io_->seek(4,BasicIo::cur); + } + else io_->seek(8,BasicIo::cur); + writeLongData(xmpData_["Xmp.audio.SampleCount"],4); + } + else{ + writeLongData(xmpData_["Xmp.video.Codec"],4,12); + io_->read(chkId.pData_,bufMinSize); + multiplier = Exiv2::getULong(chkId.pData_, littleEndian); + + //Variation + if(xmpData_["Xmp.video.StreamSampleRate"].count() > 0){ + int32_t streamSampleRate = (int32_t)xmpData_["Xmp.video.StreamSampleRate"].toLong()*multiplier; + io_->write((Exiv2::byte*)&streamSampleRate,4); + io_->seek(4,BasicIo::cur); + } + else io_->seek(8,BasicIo::cur); + + writeLongData(xmpData_["Xmp.video.StreamSampleCount"],4,4); + writeLongData(xmpData_["Xmp.video.StreamQuality"],4); + writeLongData(xmpData_["Xmp.video.StreamSampleSize"],4); + } + } + return; +} // RiffVideo::streamHandler + +void RiffVideo::streamFormatHandler(int32_t size){ + if (!d->m_modifyMetadata){ + const int32_t bufMinSize = 4; DataBuf buf(bufMinSize+1); buf.pData_[4] = '\0'; uint64_t cur_pos = io_->tell(); - if(streamType_ == Video) { + if(d->streamType_ == Video){ io_->read(buf.pData_, bufMinSize); - - for(int i = 0; i <= 9; i++) { + for(int32_t i = 0; i <= 9; i++){ std::memset(buf.pData_, 0x0, buf.size_); - - switch(i) { - case imageWidth: //Will be used in case of debugging - io_->read(buf.pData_, bufMinSize); break; - case imageHeight: //Will be used in case of debugging - io_->read(buf.pData_, bufMinSize); break; - case planes: - io_->read(buf.pData_, 2); + switch(i){ + //Will be used in case of debugging + case imageWidth: io_->read(buf.pData_, bufMinSize); break; + case imageHeight: io_->read(buf.pData_, bufMinSize); break; + case planes: io_->read(buf.pData_, 2); xmpData_["Xmp.video.Planes"] = Exiv2::getUShort(buf.pData_, littleEndian); break; - case bitDepth: - io_->read(buf.pData_, 2); + case bitDepth: io_->read(buf.pData_, 2); xmpData_["Xmp.video.PixelDepth"] = Exiv2::getUShort(buf.pData_, littleEndian); break; - case compression: - io_->read(buf.pData_, bufMinSize); + case compression: io_->read(buf.pData_, bufMinSize); xmpData_["Xmp.video.Compressor"] = buf.pData_; break; - case imageLength: - io_->read(buf.pData_, bufMinSize); + case imageLength: io_->read(buf.pData_, bufMinSize); xmpData_["Xmp.video.ImageLength"] = Exiv2::getULong(buf.pData_, littleEndian); break; - case pixelsPerMeterX: - io_->read(buf.pData_, bufMinSize); + case pixelsPerMeterX: io_->read(buf.pData_, bufMinSize); xmpData_["Xmp.video.PixelPerMeterX"] = Exiv2::getULong(buf.pData_, littleEndian); break; - case pixelsPerMeterY: - io_->read(buf.pData_, bufMinSize); + case pixelsPerMeterY: io_->read(buf.pData_, bufMinSize); xmpData_["Xmp.video.PixelPerMeterY"] = Exiv2::getULong(buf.pData_, littleEndian); break; - case numColors: - io_->read(buf.pData_, bufMinSize); - if(Exiv2::getULong(buf.pData_, littleEndian) == 0) { - xmpData_["Xmp.video.NumOfColours"] = "Unspecified"; - } - else { - xmpData_["Xmp.video.NumOfColours"] = Exiv2::getULong(buf.pData_, littleEndian); - } + case numColors: io_->read(buf.pData_, bufMinSize); + if(Exiv2::getULong(buf.pData_, littleEndian) == 0) xmpData_["Xmp.video.NumOfColours"] = "Unspecified"; + else xmpData_["Xmp.video.NumOfColours"] = Exiv2::getULong(buf.pData_, littleEndian); break; - case numImportantColors: - io_->read(buf.pData_, bufMinSize); - if(Exiv2::getULong(buf.pData_, littleEndian)) { - xmpData_["Xmp.video.NumIfImpColours"] = Exiv2::getULong(buf.pData_, littleEndian); - } - else { - xmpData_["Xmp.video.NumOfImpColours"] = "All"; - } + case numImportantColors: io_->read(buf.pData_, bufMinSize); + if(Exiv2::getULong(buf.pData_, littleEndian)) xmpData_["Xmp.video.NumIfImpColours"] = Exiv2::getULong(buf.pData_, littleEndian); + else xmpData_["Xmp.video.NumOfImpColours"] = "All"; break; } } } - else if(streamType_ == Audio) { - int c = 0; + else if(d->streamType_ == Audio){ + int32_t c = 0; const TagDetails* td; - for(int i = 0; i <= 7; i++) { + for(int32_t i = 0; i <= 7; i++){ io_->read(buf.pData_, 2); - switch(i) { - case encoding: - td = find(audioEncodingValues , Exiv2::getUShort(buf.pData_, littleEndian)); - if(td) { - xmpData_["Xmp.audio.Compressor"] = exvGettext(td->label_); - } - else { - xmpData_["Xmp.audio.Compressor"] = Exiv2::getUShort(buf.pData_, littleEndian); - } + switch(i){ + case encoding: td = find(audioEncodingValues , Exiv2::getUShort(buf.pData_, littleEndian)); + if(td) xmpData_["Xmp.audio.Compressor"] = exvGettext(td->label_); + else xmpData_["Xmp.audio.Compressor"] = Exiv2::getUShort(buf.pData_, littleEndian); break; - case numberOfChannels: - c = Exiv2::getUShort(buf.pData_, littleEndian); + case numberOfChannels: c = Exiv2::getUShort(buf.pData_, littleEndian); if(c == 1) xmpData_["Xmp.audio.ChannelType"] = "Mono"; else if(c == 2) xmpData_["Xmp.audio.ChannelType"] = "Stereo"; else if(c == 5) xmpData_["Xmp.audio.ChannelType"] = "5.1 Surround Sound"; else if(c == 7) xmpData_["Xmp.audio.ChannelType"] = "7.1 Surround Sound"; else xmpData_["Xmp.audio.ChannelType"] = "Mono"; break; - case audioSampleRate: - xmpData_["Xmp.audio.SampleRate"] = Exiv2::getUShort(buf.pData_, littleEndian); - break; - case avgBytesPerSec: - xmpData_["Xmp.audio.SampleType"] = Exiv2::getUShort(buf.pData_, littleEndian); - break; - case bitsPerSample: - xmpData_["Xmp.audio.BitsPerSample"] = Exiv2::getUShort(buf.pData_,littleEndian); - io_->read(buf.pData_, 2); - break; + case audioSampleRate: xmpData_["Xmp.audio.SampleRate"] = Exiv2::getUShort(buf.pData_, littleEndian); break; + case avgBytesPerSec: xmpData_["Xmp.audio.SampleType"] = Exiv2::getUShort(buf.pData_, littleEndian); break; + case bitsPerSample: xmpData_["Xmp.audio.BitsPerSample"] = Exiv2::getUShort(buf.pData_,littleEndian); + io_->read(buf.pData_, 2); break; } } } io_->seek(cur_pos + size, BasicIo::beg); - } // RiffVideo::streamFormatHandler + } + else{ + if(d->streamType_ == Video){ + DataBuf chkId((uint64_t) 5); + chkId.pData_[4] = '\0'; + io_->read(chkId.pData_,4); - double RiffVideo::returnSampleRate(Exiv2::DataBuf& buf, long divisor) - { - return ((double)Exiv2::getULong(buf.pData_, littleEndian) / (double)divisor); - } // RiffVideo::returnSampleRate + writeLongData(xmpData_["Xmp.video.Width"],4); + writeLongData(xmpData_["Xmp.video.Height"],4); + writeShortData(xmpData_["Xmp.video.Planes"]); + writeShortData(xmpData_["Xmp.video.PixelDepth"]); + writeStringData(xmpData_["Xmp.video.Compressor"],4); + writeLongData(xmpData_["Xmp.video.ImageLength"],4); + writeLongData(xmpData_["Xmp.video.PixelPerMeterX"],4); + writeLongData(xmpData_["Xmp.video.PixelPerMeterY"],4); + writeLongData(xmpData_["Xmp.video.NumOfColours"],4); - const char* RiffVideo::printAudioEncoding(uint64_t i) - { - const TagDetails* td; - td = find(audioEncodingValues , i); - if(td) - return exvGettext(td->label_); - - return "Undefined"; - } // RiffVideo::printAudioEncoding - - void RiffVideo::fillAspectRatio(long width, long height) - { - double aspectRatio = (double)width / (double)height; - aspectRatio = floor(aspectRatio*10) / 10; - xmpData_["Xmp.video.AspectRatio"] = aspectRatio; - - int aR = (int) ((aspectRatio*10.0)+0.1); - - switch (aR) { - case 13 : xmpData_["Xmp.video.AspectRatio"] = "4:3" ; break; - case 17 : xmpData_["Xmp.video.AspectRatio"] = "16:9" ; break; - case 10 : xmpData_["Xmp.video.AspectRatio"] = "1:1" ; break; - case 16 : xmpData_["Xmp.video.AspectRatio"] = "16:10" ; break; - case 22 : xmpData_["Xmp.video.AspectRatio"] = "2.21:1" ; break; - case 23 : xmpData_["Xmp.video.AspectRatio"] = "2.35:1" ; break; - case 12 : xmpData_["Xmp.video.AspectRatio"] = "5:4" ; break; - default : xmpData_["Xmp.video.AspectRatio"] = aspectRatio;break; - } - } // RiffVideo::fillAspectRatio - - void RiffVideo::fillDuration(double frame_rate, long frame_count) - { - if(frame_rate == 0) - return; - - uint64_t duration = static_cast((double)frame_count * (double)1000 / (double)frame_rate); - xmpData_["Xmp.video.FileDataRate"] = (double)io_->size()/(double)(1048576*duration); - xmpData_["Xmp.video.Duration"] = duration; //Duration in number of seconds - } // RiffVideo::fillDuration - - Image::AutoPtr newRiffInstance(BasicIo::AutoPtr io, bool /*create*/) - { - Image::AutoPtr image(new RiffVideo(io)); - if (!image->good()) { - image.reset(); + //Variation + if(xmpData_["Xmp.video.NumOfImpColours"].count() > 0){ + if(std::strcmp(xmpData_["Xmp.video.NumOfImpColours"].toString().c_str(),"All")){ + const int32_t numImportantColours = (int32_t) 0; + io_->write((Exiv2::byte*)&numImportantColours,4); + } + else writeLongData(xmpData_["Xmp.video.NumOfImpColours"],4); + } + else io_->seek(4,BasicIo::cur); } - return image; + else if(d->streamType_ == Audio){ + const RevTagDetails* rtd; + //Variation + if(xmpData_["Xmp.audio.Compressor"].count() > 0){ + RevTagDetails revTagDetails[(sizeof(audioEncodingValues)/ + sizeof(audioEncodingValues[0]))]; + reverseTagDetails(audioEncodingValues,revTagDetails, + (sizeof(audioEncodingValues) + /sizeof(audioEncodingValues[0]))); + rtd = find(revTagDetails,xmpData_["Xmp.audio.Compressor"].toString()); + if(rtd){ + uint16_t compressorCode= (uint16_t)rtd->val_; + io_->write((Exiv2::byte*)&compressorCode,2); + } + else io_->seek(2,BasicIo::cur); + } + else io_->seek(2,BasicIo::cur); + + if(xmpData_["Xmp.audio.ChannelType"].count() > 0){ + const int32_t sizeChan = xmpData_["Xmp.audio.ChannelType"].size(); + DataBuf tmpBuf(sizeChan+1); + tmpBuf.pData_[sizeChan+1] = '\0'; + const std::string audioChannealType = xmpData_["Xmp.audio.ChannelType"].toString(); + int32_t i; + for( i=0; i<=sizeChan;i++) tmpBuf.pData_[i] = (Exiv2::byte)audioChannealType[i]; + uint16_t channelType = 0; + if(UtilsVideo::simpleBytesComparision(tmpBuf,"MONO",sizeChan)) channelType = 1; + else if(UtilsVideo::simpleBytesComparision(tmpBuf,"STEREO",sizeChan)) channelType = 2; + else if(UtilsVideo::simpleBytesComparision(tmpBuf,"5.1 SURROUND SOUND",sizeChan)) channelType = 5; + else if(UtilsVideo::simpleBytesComparision(tmpBuf,"7.1 SURROUND SOUND",sizeChan)) channelType = 7; + io_->write((Exiv2::byte*)&channelType,2); + } + else io_->seek(2,BasicIo::cur); + + writeShortData(xmpData_["Xmp.audio.SampleRate"],2,2); + writeShortData(xmpData_["Xmp.audio.SampleType"],2,4); + writeShortData(xmpData_["Xmp.audio.BitsPerSample"],2); + } + } + return; +} // RiffVideo::streamFormatHandler + +double RiffVideo::returnSampleRate(Exiv2::DataBuf& buf, int32_t divisor){ + return ((double)Exiv2::getULong(buf.pData_, littleEndian) / (double)divisor); +} // RiffVideo::returnSampleRate + +const char* RiffVideo::printAudioEncoding(uint64_t i){ + const TagDetails* td; + td = find(audioEncodingValues , i); + if(td) return exvGettext(td->label_); + + return "Undefined"; +} // RiffVideo::printAudioEncoding + +void RiffVideo::fillAspectRatio(int32_t width, int32_t height){ + double aspectRatio = (double)width / (double)height; + aspectRatio = floor(aspectRatio*10) / 10; + xmpData_["Xmp.video.AspectRatio"] = aspectRatio; + + int32_t aR = (int32_t) ((aspectRatio*10.0)+0.1); + + switch (aR) { + case 13 : xmpData_["Xmp.video.AspectRatio"] = "4:3" ; break; + case 17 : xmpData_["Xmp.video.AspectRatio"] = "16:9" ; break; + case 10 : xmpData_["Xmp.video.AspectRatio"] = "1:1" ; break; + case 16 : xmpData_["Xmp.video.AspectRatio"] = "16:10" ; break; + case 22 : xmpData_["Xmp.video.AspectRatio"] = "2.21:1" ; break; + case 23 : xmpData_["Xmp.video.AspectRatio"] = "2.35:1" ; break; + case 12 : xmpData_["Xmp.video.AspectRatio"] = "5:4" ; break; + default : xmpData_["Xmp.video.AspectRatio"] = aspectRatio;break; + } + return; +} // RiffVideo::fillAspectRatio + +void RiffVideo::fillDuration(double frame_rate, int32_t frame_count){ + if(frame_rate == 0) return; + + uint64_t duration = static_cast((double)frame_count * (double)1000 / (double)frame_rate); + xmpData_["Xmp.video.FileDataRate"] = (double)io_->size()/(double)(1048576*duration); + xmpData_["Xmp.video.Duration"] = duration; //Duration in number of seconds + return; +} // RiffVideo::fillDuration + +void RiffVideo::reverseTagDetails(const TagDetails inputTagVocabulary[], + RevTagDetails outputTagVocabulary[] ,int32_t size){ + for(int32_t i=0; igood()) image.reset(); + return image; +} + +/*! + * \brief RiffVideo::copyRestOfTheFile + * Move all data to next locations,Currently its blockwise copy,which is inefficient for a + * huge video files,and should be changed to inserting technique without moving huge data + * like Bundle technology as suggested by Robin. + * \param oldSavedData + * \return + */ +bool RiffVideo::copyRestOfTheFile(DataBuf oldSavedData){ + + int32_t writeSize = oldSavedData.size_; + int32_t readSize = writeSize; + DataBuf readBuf((int32_t)max(readSize,(int32_t)1024)); + DataBuf writeBuf((int32_t)max(readSize,(int32_t)1024)); + + memcpy(writeBuf.pData_,oldSavedData.pData_,readSize); + bool lastStream = false,hasData = true; + + while(hasData){ + if((io_->size() - io_->tell()) < 1024){ + hasData = false; + lastStream = true; + readSize = (io_->size() - io_->tell()); + } + + io_->read(readBuf.pData_,readSize); + io_->seek(-readSize,BasicIo::cur); + io_->write(writeBuf.pData_,writeSize); + + memcpy(writeBuf.pData_,readBuf.pData_,readSize); + writeSize = readSize; + if(lastStream) io_->write(writeBuf.pData_,readSize); + } + return true; +} + +/*! + * \brief RiffVideo::writeNewSubChunks + * precondition:INFO List chunk must exist,atleast with LIST tag, + * and size field with size one(INFO tag which appear next) + * + * |----LIST(Must exist before calling this method) + * |----Size(Must exist, atleast with size 1 if no INFO subchunks exist before) + * |----INFO (Must exist,exactly with same HeaderChunkId INFO) + * + * \param chunkData + * \return + */ +bool RiffVideo::writeNewSubChunks(std::vector > chunkData){ + bool result = true; + int32_t addSize = 0; + for (vector >::iterator it = chunkData.begin(); + it != chunkData.end(); it++){ + std::pair unitChunk = (*it); + addSize += (int32_t)unitChunk.first.size() + (int32_t)8; + addSize += addSize%2; + } + const int32_t cur_pos = io_->tell(); + DataBuf buf((uint64_t)5); + buf.pData_[4] = '\0'; + io_->seek(4,BasicIo::beg); + io_->read(buf.pData_,4); + io_->seek(-4,BasicIo::cur); + + const int32_t originalSize = Exiv2::getULong(buf.pData_, littleEndian); + int32_t newRiffSize = originalSize + addSize ; + io_->write((Exiv2::byte*)&newRiffSize,4); + + io_->seek(cur_pos,BasicIo::beg); + io_->read(buf.pData_,4); + io_->seek(-4,BasicIo::cur); + + const int32_t originalListSize = Exiv2::getULong(buf.pData_, littleEndian); + int32_t newListSize = originalListSize + addSize ; + io_->write((Exiv2::byte*)&newListSize,4); + + io_->read(buf.pData_,4); + std::vector previousData; + uint64_t i; + + for (vector >::iterator it = chunkData.begin(); + it != chunkData.end(); it++){ + std::pair unitChunk = (*it); + std::string chunkId = unitChunk.second; + std::string tmpChunkData = unitChunk.first; + uint64_t chunkSize = tmpChunkData.size(); + chunkSize += chunkSize%2; + + DataBuf copiedData((int32_t)(chunkSize+8)); + + io_->read(copiedData.pData_,(chunkSize+8)); + io_->seek(((-1)*(chunkSize+8)),BasicIo::cur); + previousData.push_back(copiedData); + Exiv2::byte rawChunkId[4] = {(Exiv2::byte)chunkId[0],(Exiv2::byte)chunkId[1], + (Exiv2::byte)chunkId[2],(Exiv2::byte)chunkId[3]}; + Exiv2::byte* rawChunkData = new byte[(int32_t)chunkSize]; + + for(i=0; i < chunkSize; i++) rawChunkData[i] = (Exiv2::byte)tmpChunkData[i]; + if(tmpChunkData.size()%2 != 0) rawChunkData[(int32_t)(chunkSize-1)] = (Exiv2::byte)0; + + io_->write(rawChunkId,4); + io_->write((Exiv2::byte*)&chunkSize,4); + io_->write(rawChunkData,chunkSize); + delete[] rawChunkData; } - bool isRiffType(BasicIo& iIo, bool advance) - { - const int32_t len = 2; - const unsigned char RiffVideoId[4] = { 'R', 'I', 'F' ,'F'}; - byte buf[len]; - iIo.read(buf, len); - if (iIo.error() || iIo.eof()) { - return false; + int32_t accessIndex = 0; + int32_t netNewMetadataSize = 0; + for (i=0; i < (int32_t)previousData.size(); i++) netNewMetadataSize += previousData[i].size_; + + DataBuf metadataPacket((uint64_t)netNewMetadataSize); + for (i=0; i < previousData.size(); i++){ + for(int32_t assignIndex=0; assignIndex 0){ + std::string dataString = xmpStringData.toString(); + Exiv2::byte* rawData = new byte[(uint8_t)size]; + int32_t newSize = (int32_t)dataString.size(); + for(int32_t i=0; i newSize) for(int32_t i=newSize; iwrite(rawData,size); + io_->seek((int)skipOffset,BasicIo::cur); + delete[] rawData; + } + else io_->seek((size+skipOffset),BasicIo::cur); +} + +void RiffVideo::writeLongData(Exiv2::Xmpdatum xmpIntData, int32_t size, int32_t skipOffset){ + if(xmpIntData.count() > 0){ + int32_t rawIntData = (int32_t)xmpIntData.toLong(); + io_->write((Exiv2::byte*)&rawIntData,size); + io_->seek(skipOffset,BasicIo::cur); + } + else io_->seek((size+skipOffset),BasicIo::cur); +} + +void RiffVideo::writeFloatData(Exiv2::Xmpdatum xmpIntData, int32_t size, int32_t skipOffset){ + if(xmpIntData.count() > 0){ + int32_t rawIntData = (int32_t)xmpIntData.toFloat(); + io_->write((Exiv2::byte*)&rawIntData,size); + io_->seek(skipOffset,BasicIo::cur); + } + else io_->seek((size+skipOffset),BasicIo::cur); +} + +void RiffVideo::writeShortData(Exiv2::Xmpdatum xmpIntData, int16_t size, int32_t skipOffset){ + if(xmpIntData.count() > 0){ + int16_t rawIntData = (int16_t)xmpIntData.toLong(); + io_->write((Exiv2::byte*)&rawIntData,size); + io_->seek(skipOffset,BasicIo::cur); + } + else io_->seek((size+skipOffset),BasicIo::cur); +} + +bool isRiffType(BasicIo& iIo, bool advance){ + const int32_t len = 2; + const unsigned char RiffVideoId[4] = { 'R', 'I', 'F' ,'F'}; + Exiv2::byte* buf = new byte[len]; + iIo.read(buf, len); + if (iIo.error() || iIo.eof()){ + delete[] buf; + return false; + } + bool matched = (memcmp(buf, RiffVideoId, len) == 0); + if (!advance || !matched) iIo.seek(-len, BasicIo::cur); + delete[] buf; + return matched; +} } // namespace Exiv2 + diff --git a/src/riffvideo.hpp b/src/riffvideo.hpp index 785d27ce..7b6f25f7 100644 --- a/src/riffvideo.hpp +++ b/src/riffvideo.hpp @@ -22,8 +22,11 @@ @file riffvideo.hpp @brief An Image subclass to support RIFF video files @version $Rev$ - @author Abhinav Badola for GSoC 2012 + @authors Abhinav Badola for GSoC 2012 mail.abu.to@gmail.com + + Mahesh Hegde for GSoC 2013 + maheshmhegade@gmail.com @date 18-Jun-12, AB: created */ #ifndef RIFFVIDEO_HPP @@ -42,20 +45,78 @@ namespace Exiv2 { // ***************************************************************************** // class definitions - // Add RIFF to the supported image formats - namespace ImageType { - const int riff = 20; //!< Treating riff as an image type> - } +// Add RIFF to the supported image formats +namespace ImageType { +const int riff = 20; //!< Treating riff as an image type> +} - /*! +using namespace std; +/*! @brief Class to access RIFF video files. */ - class EXIV2API RiffVideo:public Image +class EXIV2API RiffVideo:public Image +{ +public: + + //List, Header,Primitive and Junk chunks inside m_riffFileSkeleton reveal entire RIFF structure + /*! + * \brief The PrimitiveChunk class Hold the information about a unit chunk. + */ + class PrimitiveChunk { public: - //! @name Creators - //@{ - /*! + PrimitiveChunk(){} + ~PrimitiveChunk(){} + + public: + byte m_chunkId[5]; //!< Primitive chunk ID. + uint64_t m_chunkLocation; //!< Chunk location in afile. + uint64_t m_chunkSize; //!< Chunk size. + }; + + /*! + * \brief The HeaderChunk class Hold the information about Header chunk + * Containing multiple primitive chunks. + */ + class HeaderChunk + { + public: + HeaderChunk(){} + ~HeaderChunk(){} + + public: + byte m_headerId[5]; //!< Chunk Header Id + unsigned long m_headerLocation; //!< Header Chunk Location in a file. + unsigned long m_headerSize; //!< Header Chunk size + }; + + /*! + * \brief The RiffMetaSkeleton class Hold information about all the + * chunks present in a file. + */ + class RiffMetaSkeleton + { + public: + RiffMetaSkeleton(){} + ~RiffMetaSkeleton(){} + + public: + vector m_headerChunks; //!< vector containing all Header chunks. + vector m_primitiveChunks; //!< vector Containing all the primitve chunks + }; + + /*! + * \brief The IoPosition enum reveal the position,while traversing the file. + */ + enum IoPosition + { + LastChunk, //!< "MOVI" or "DATA" + TraversingChunk, //!< "AVI" "hdrl" etc which further have sub-chunks + PremitiveChunk //!< Remaining chunks which do not have subchunk + }; + //! @name Creators + //@{ + /*! @brief Constructor for a Riff video. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @@ -66,149 +127,227 @@ namespace Exiv2 { instance after it is passed to this method. Use the Image::io() method to get a temporary reference. */ - RiffVideo(BasicIo::AutoPtr io); - //@} + RiffVideo(BasicIo::AutoPtr io); + //@} - //! @name Manipulators - //@{ - void readMetadata(); - void writeMetadata(); - //@} + ~RiffVideo(); - //! @name Accessors - //@{ - std::string mimeType() const; - const char* printAudioEncoding(uint64_t i); - //@} + //! @name Manipulators + //@{ + void readMetadata(); + void writeMetadata(); + //@} - protected: - /*! + //! @name Accessors + //@{ + std::string mimeType() const; + const char* printAudioEncoding(uint64_t i); + //@} + +protected: + /*! @brief Check for a valid tag and decode the block at the current IO position. Calls tagDecoder() or skips to next tag, if required. */ - void decodeBlock(); - /*! - @brief Interpret tag information, and call the respective function - to save it in the respective XMP container. Decodes a Tag - Information and saves it in the respective XMP container, if - the block size is small. - @param buf Data buffer which cotains tag ID. - @param size Size of the data block used to store Tag Information. - */ - void tagDecoder(Exiv2::DataBuf& buf, unsigned long size); - /*! + void decodeBlock(); + /*! + * \brief tagDecoder Main method to call corresponding handler methos for decoding tags. + */ + void tagDecoder(); + /*! @brief Interpret Junk tag information, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void junkHandler(long size); - /*! + void junkHandler(int32_t size); + + /*! find whether stream is audio or video + */ + void setStreamType(); + /*! @brief Interpret Stream tag information, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void streamHandler(long size); - /*! + void streamHandler(int32_t size); + /*! @brief Interpret Stream Format tag information, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void streamFormatHandler(long size); - /*! + void streamFormatHandler(int32_t size); + /*! @brief Interpret Riff Header tag information, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void aviHeaderTagsHandler(long size); - /*! + void aviHeaderTagsHandler(int32_t size); + /*! @brief Interpret Riff List tag information, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void listHandler(long size); - /*! + void listHandler(long size); + /*! @brief Interpret Riff Stream Data tag information, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. */ - void streamDataTagHandler(long size); - /*! + void streamDataTagHandler(int32_t size); + /*! @brief Interpret INFO tag information, and save it in the respective XMP container. */ - void infoTagsHandler(); - /*! + void infoTagsHandler(); + /*! @brief Interpret Nikon Tags related to Video information, and save it in the respective XMP container. */ - void nikonTagsHandler(); - /*! + void nikonTagsHandler(); + /*! @brief Interpret OpenDML tag information, and save it in the respective XMP container. */ - void odmlTagsHandler(); - //! @brief Skips Particular Blocks of Metadata List. - void skipListData(); - /*! + void odmlTagsHandler(); + //! @brief Skips Particular Blocks of Metadata List. + void skipListData(); + /*! @brief Interprets DateTimeOriginal tag or stream name tag information, and save it in the respective XMP container. @param size Size of the data block used to store Tag Information. @param i parameter used to overload function */ - void dateTimeOriginal(long size, int i = 0); - /*! + void dateTimeOriginal(int32_t size, int32_t i = 0); + /*! @brief Calculates Sample Rate of a particular stream. @param buf Data buffer with the dividend. @param divisor The Divisor required to calculate sample rate. @return Return the sample rate of the stream. */ - double returnSampleRate(Exiv2::DataBuf& buf, long divisor = 1); - /*! + double returnSampleRate(Exiv2::DataBuf& buf, int32_t divisor = 1); + /*! @brief Calculates Aspect Ratio of a video, and stores it in the respective XMP container. @param width Width of the video. @param height Height of the video. */ - void fillAspectRatio(long width = 1,long height = 1); - /*! + void fillAspectRatio(int32_t width = 1, int32_t height = 1); + /*! @brief Calculates Duration of a video, and stores it in the respective XMP container. @param frame_rate Frame rate of the video. @param frame_count Total number of frames present in the video. */ - void fillDuration(double frame_rate, long frame_count); + void fillDuration(double frame_rate, int32_t frame_count); - private: - //! @name NOT Implemented - //@{ - //! Copy constructor - RiffVideo(const RiffVideo& rhs); - //! Assignment operator - RiffVideo& operator=(const RiffVideo& rhs); - //@} + /*! + * \brief copyRestOfTheFile copy rest of the file content as it is + * \param oldSavedData saved data from file, where data is already written into the file. + * \return + */ + bool copyRestOfTheFile(DataBuf oldSavedData); - private: - //! Variable to check the end of metadata traversing. - bool continueTraversing_; - //! Variable which stores current stream being processsed. - int streamType_; + /*! + * \brief reverseTagDetails reverse the position of members of a structure + * \param inputTagVocabulary + * \param outputTagVocabulary + * \param size + */ + void reverseTagDetails(const Internal::TagDetails inputTagVocabulary[], + Internal::RevTagDetails outputTagVocabulary[] , int32_t size); - }; //Class RiffVideo +private: + //! @name NOT Implemented + //@{ + //! Copy constructor + RiffVideo(const RiffVideo& rhs); + //! Assignment operator + RiffVideo& operator=(const RiffVideo& rhs); + //@} + /*! + @brief Provides the main implementation of writeMetadata() by + writing all buffered metadata to the provided BasicIo. + @param oIo BasicIo instance to write to (a temporary location). + + @return 4 if opening or writing to the associated BasicIo fails + */ + EXV_DLLLOCAL void doWriteMetadata(); + + /*! + * \brief findChunkPositions Finds the primitive shunk position in a file. + * \param chunkId Id of chunk to be searched + * \return + */ + std::vector findChunkPositions(const char *chunkId); + + /*! + * \brief findHeaderPositions Finds the location of Header chunk in a file. + * \param headerId Id of Header Chunk to be searched. + * \return + */ + std::vector findHeaderPositions(const char* headerId); + + /*! + * \brief writeNewSubChunks Writes the new chunk,also hold the data from overwritten + * location in a file. + * \param chunkData vector containing chunk ID and chunk Data + * \return + */ + bool writeNewSubChunks(std::vector > chunkData); + + /*! + * \brief writeStringData + * \param stringData + * \param skipOffset + */ + void writeStringData(Exiv2::Xmpdatum xmpStringData, int32_t size, int32_t skipOffset=0); + + /*! + * \brief writeLongData + * \param xmpIntData + * \param size + * \param skipOffset + */ + void writeLongData(Exiv2::Xmpdatum xmpIntData, int32_t size=4, int32_t skipOffset=0); + + /*! + * \brief writeFloatData + * \param xmpIntData + * \param size + * \param skipOffset + */ + void writeFloatData(Exiv2::Xmpdatum xmpIntData, int32_t size=4, int32_t skipOffset=0); + + /*! + * \brief writeShortData + * \param xmpIntData + * \param size + * \param skipOffset + */ + void writeShortData(Exiv2::Xmpdatum xmpIntData, int16_t size=2, int32_t skipOffset=0); + +private: + + // Good idea to use private(Refer KDE documentaion https://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++ ) + class Private; + Private* const d; + +}; //Class RiffVideo // ***************************************************************************** // template, inline and free functions - // These could be static private functions on Image subclasses but then - // ImageFactory needs to be made a friend. - /*! +// These could be static private functions on Image subclasses but then +// ImageFactory needs to be made a friend. +/*! @brief Create a new RiffVideo instance and return an auto-pointer to it. Caller owns the returned object and the auto-pointer ensures that it will be deleted. */ - EXIV2API Image::AutoPtr newRiffInstance(BasicIo::AutoPtr io, bool create); +EXIV2API Image::AutoPtr newRiffInstance(BasicIo::AutoPtr io, bool create); - //! Check if the file iIo is a Riff Video. - EXIV2API bool isRiffType(BasicIo& iIo, bool advance); +//! Check if the file iIo is a Riff Video. +EXIV2API bool isRiffType(BasicIo& iIo, bool advance); } // namespace Exiv2 diff --git a/src/tags_int.hpp b/src/tags_int.hpp index 9e8fb484..f3db507e 100644 --- a/src/tags_int.hpp +++ b/src/tags_int.hpp @@ -191,6 +191,18 @@ namespace Exiv2 { bool operator==(long key) const { return val_ == key; } }; // struct TagDetails + /*! + @brief Helper structure for lookup tables for translations of numeric + tag values to human readable labels. + */ + + struct RevTagDetails { + const char* label_; //!< Translation of the tag value + long val_; //!< Tag value + + //! Comparison operator for use with the find template + bool operator==(const std::string& key) const{return label_ == key;} + }; /*! @brief Helper structure for lookup tables for translations of bitmask values to human readable labels. diff --git a/src/types.cpp b/src/types.cpp index c5a70151..61f3f6ac 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -125,10 +125,12 @@ namespace Exiv2 { return tit->size_; } - DataBuf::DataBuf(DataBuf& rhs) + DataBuf::DataBuf(const DataBuf& rhs) : pData_(rhs.pData_), size_(rhs.size_) { - rhs.release(); + pData_ = new byte[rhs.size_]; + size_ = rhs.size_; + std::copy(rhs.pData_,rhs.pData_+rhs.size_,pData_); } DataBuf::DataBuf(const byte* pData, long size) @@ -156,6 +158,7 @@ namespace Exiv2 { size_ = 0; pData_ = new byte[size]; size_ = size; + std::memset(pData_, 0x0, size_); } } diff --git a/src/types.hpp b/src/types.hpp index 8bf258b3..42bd3355 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #ifdef EXV_HAVE_STDINT_H # include @@ -209,7 +210,7 @@ namespace Exiv2 { //! Default constructor DataBuf() : pData_(0), size_(0) {} //! Constructor with an initial buffer size - explicit DataBuf(long size) : pData_(new byte[size]), size_(size) {} + explicit DataBuf(long size) : pData_(new byte[size]), size_(size) { std::memset(pData_, 0x0, size_); } //! Constructor, copies an existing buffer DataBuf(const byte* pData, long size); /*! @@ -217,7 +218,7 @@ namespace Exiv2 { object similar to std::auto_ptr, i.e., the original object is modified. */ - DataBuf(DataBuf& rhs); + DataBuf(const DataBuf& rhs); //! Destructor, deletes the allocated buffer ~DataBuf() { delete[] pData_; } //@} diff --git a/src/utilsvideo.cpp b/src/utilsvideo.cpp new file mode 100644 index 00000000..b9f70b98 --- /dev/null +++ b/src/utilsvideo.cpp @@ -0,0 +1,60 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2014 Andreas Huggel + * + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/*! + @file utilsvideo.hpp + @brief An Image subclass to support RIFF video files + @version $Rev$ + Mahesh Hegde 2014 + maheshmhegade@gmail.com + @date 16-Aug-14, AB: created + */ +#include "utilsvideo.hpp" + +#ifndef _MSC_VER +#define stricmp strcasecmp +#endif + +namespace Exiv2 +{ + +bool UtilsVideo::compareTagValue(Exiv2::DataBuf& buf ,const char* str){ + bool result = true; + for(int32_t i=0; result && i<4; i++ ) + if(tolower(buf.pData_[i]) != tolower(str[i])) + return false; + return true; +} + +bool UtilsVideo::compareTagValue(Exiv2::DataBuf& buf,const char arr[][5],int32_t arraysize){ + bool result = false; + for ( int32_t i=0; !result && i< arraysize; i++) + result = (bool)(stricmp((const char*)buf.pData_,arr[i])==0); + return result; +} + +bool UtilsVideo::simpleBytesComparision(Exiv2::DataBuf& buf ,const char* str,int32_t size){ + for(int32_t i=0; i + * + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/*! + @file utilsvideo.hpp + @brief An Image subclass to support RIFF video files + @version $Rev$ + Mahesh Hegde 2014 + maheshmhegade@gmail.com + @date 16-Aug-14, AB: created + */ +#include "tags_int.hpp" + +namespace Exiv2 +{ + +class UtilsVideo +{ +public: + static bool compareTagValue(Exiv2::DataBuf &buf, const char *str); + static bool compareTagValue(Exiv2::DataBuf& buf,const char arr[][5],int32_t arraysize); + static bool simpleBytesComparision(Exiv2::DataBuf& buf ,const char* str,int32_t size); +}; // class UtilsVideo + +} // namespace Exiv2 diff --git a/src/version.hpp b/src/version.hpp index 8ab16c82..55f24baa 100644 --- a/src/version.hpp +++ b/src/version.hpp @@ -187,6 +187,7 @@ namespace Exiv2 { // dumpLibraryInfo is general purpose and not in the Exiv2 namespace // used by exiv2 test suite to inspect libraries loaded at run-time +//! TO be completed. EXIV2API void dumpLibraryInfo(std::ostream& os); diff --git a/src/xmp.cpp b/src/xmp.cpp index 870aad48..5a060471 100644 --- a/src/xmp.cpp +++ b/src/xmp.cpp @@ -416,6 +416,8 @@ namespace Exiv2 { SXMPMeta::RegisterNamespace("http://ns.microsoft.com/photo/1.2/t/Region#", "MPReg"); SXMPMeta::RegisterNamespace("http://www.metadataworkinggroup.com/schemas/regions/", "mwg-rs"); SXMPMeta::RegisterNamespace("http://ns.adobe.com/xmp/sType/Area#", "stArea"); + SXMPMeta::RegisterNamespace("http://www.video/", "video"); + SXMPMeta::RegisterNamespace("http://www.audio/", "audio"); #else initialized_ = true; #endif diff --git a/test/Makefile b/test/Makefile index a0b8e12b..328fb561 100644 --- a/test/Makefile +++ b/test/Makefile @@ -65,24 +65,25 @@ SVN = svn://dev.exiv2.org/svn/testdata/trunk ## # Add test drivers to this list -TESTS = addmoddel.sh \ - bugfixes-test.sh \ - exifdata-test.sh \ - exiv2-test.sh \ - imagetest.sh \ - iotest.sh \ - iptctest.sh \ - modify-test.sh \ - path-test.sh \ - preview-test.sh \ - stringto-test.sh \ - tiff-test.sh \ - write-test.sh \ - write2-test.sh \ - xmpparser-test.sh \ - conversions.sh -TESTV = video-test.sh -TESTE = eps-test.sh +TESTS = addmoddel.sh \ + bugfixes-test.sh \ + exifdata-test.sh \ + exiv2-test.sh \ + imagetest.sh \ + iotest.sh \ + iptctest.sh \ + modify-test.sh \ + path-test.sh \ + preview-test.sh \ + stringto-test.sh \ + tiff-test.sh \ + write-test.sh \ + write2-test.sh \ + xmpparser-test.sh \ + conversions.sh +TESTV = video-test.sh +TESTE = eps-test.sh +TESTVW = write-video-test.sh tests: cd .. ; make tests @@ -99,15 +100,26 @@ test: testv: @for t in /video ; do \ if [ ! -e data/$$t ]; then \ - echo svn export '$(SVN)'$$t data$$t -r 3100 ; \ - svn export '$(SVN)'$$t data$$t -r 3100 ; \ + echo svn export '$(SVN)'$$t data$$t ; \ + svn export '$(SVN)'$$t data$$t ; \ fi ; done @list='$(TESTV)'; for p in $$list; do \ echo Running $$p ...; \ ./$$p; \ done +testvw: + @for t in /video ; do \ + if [ ! -e data/$$t ]; then \ + echo svn export '$(SVN)'$$t data$$t ; \ + svn export '$(SVN)'$$t data$$t ; \ + fi ; done + @list='$(TESTVW)'; for p in $$list; do \ + echo Running $$p ...; \ + ./$$p; \ + done ## + # TODO: download eps data on demand for 0.24 (similar to testv) teste: @list='$(TESTE)'; for p in $$list; do \ diff --git a/test/functions.source b/test/functions.source index 162d9594..5e6a05f3 100644 --- a/test/functions.source +++ b/test/functions.source @@ -52,7 +52,8 @@ copyTestFile() if [ $# == 2 ]; then cp -f "$here/data/$1" "$here/tmp/$2" elif [ $# == 1 ]; then - cp -f "$here/data/$1" "$here/tmp/$1" + stub=$(basename $1) + cp -f "$here/data/$1" "$here/tmp/$stub" else echo "*** error copyTestFile: illegal number of inputs = $# ***" fi @@ -213,14 +214,14 @@ iptcTest() # Make sure to pass the test file first and the known good file second diffCheck() { - test=$1 - good=$2 + test=$(real_path $1) + good=$(real_path $2) if [ -z "$errors" ]; then let -a errors=0; fi #run diff and check results - diff -q --binary $diffargs $test $good + diff -q --binary $diffargs "$test" "$good" if [ $? -ne 0 ]; then - errors=`expr $errors + 1` + errors=$(expr $errors + 1) else rm $test fi @@ -341,39 +342,49 @@ extendedTest() rm $tmp } + ## -# http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac +# real_path - report the absolute path to a file real_path () { - OIFS=$IFS - IFS='/' - for I in $1; do - # Resolve relative path punctuation. - if [ "$I" = "." ] || [ -z "$I" ]; then - continue - elif [ "$I" = ".." ]; then - FOO="${FOO%%/${FOO##*/}}" - continue - else - FOO="${FOO}/${I}" - fi + which realpath 2>/dev/null >/dev/null + if [ $? == 0 ]; then + realpath "$1" + else + readlink -f "$1" + fi +} - ## Resolve symbolic links - if [ -h "$FOO" ]; then - IFS=$OIFS - set `ls -l "$FOO"` - while shift ; do - if [ "$1" = "->" ]; then - FOO=$2 - shift $# - break - fi - done - IFS='/' - fi - done - IFS=$OIFS - echo "$FOO" +copyVideoFiles () +{ + pushd "$testdir" 2>/dev/null >/dev/null + + ## + # find video files data/video and copy them for testing + declare -a videos + for video in $datadir/video/* ; do + # http://stackoverflow.com/questions/965053/extract-filename-and-extension-in-bash + ext="${video##*.}" + if [ $ext != out ]; then + copyTestFile "$video" + videos+=($(basename "$video")) + fi + done + + ## + # TODO: remove debugging code + if [ "$FACTORY" == "rmills-mbp.localXX" ]; then + for v in write-video-test.out video-test.out; do + cp ~/gnu/exiv2/testdata/trunk/video/$v ~/gnu/exiv2/video13/test/data/video/ + done + fi + + # http://stackoverflow.com/questions/7442417/how-to-sort-an-array-in-bash + readarray -t sorted < <(printf '%s\0' "${videos[@]}" | sort -z | xargs -0n1) + echo ${videos[*]} + unset videos + + popd 2>/dev/null >/dev/null } ## diff --git a/test/video-test.sh b/test/video-test.sh index 4f4dde90..fa14aaf5 100755 --- a/test/video-test.sh +++ b/test/video-test.sh @@ -8,42 +8,35 @@ source ./functions.source +## +# set up output and reference file +out=$(real_path "$testdir/$this.out") +copyTestFile "video/$this.out" + ( cd "$testdir" - for file in ../data/video/video-*; do - video="`basename "$file"`" - if [ $video != "video-test.out" ] ; then - - printf "." >&3 - - echo - echo "-----> $video <-----" - - copyTestFile "video/$video" "$video" - - echo - echo "Command: exiv2 -u -pa $video" - runTest exiv2 -u -pa "$video" - exitcode="$?" - echo "Exit code: $exitcode" - - if [ "$exitcode" -ne 0 -a "$exitcode" -ne 253 ] ; then - continue - fi - fi + videos=($(copyVideoFiles)) + for video in ${videos[*]}; do + printf "." >&3 + echo + echo "-----> $video <-----" + echo + echo "Command: exiv2 -u -pa $video" + # run command | ignore binary and no Date nor NumOfColours tags + runTest exiv2 -u -pa "$video" | sed -E -e 's/\d128-\d255/_/g' | grep -a -v -e Date -v -e NumOfC done -) 3>&1 > "$testdir/video-test.out" 2>&1 - -echo "." +) 3>&1 2>&1 > "$out" # ---------------------------------------------------------------------- # Result -if ! diff -q $diffargs "$testdir/$datadir/video/video-test.out" "$testdir/video-test.out" ; then - diff -u -a $diffargs "$testdir/$datadir/video/video-test.out" "$testdir/video-test.out" - exit 1 +diffCheck "$out" "$testdir/$datadir/video/$this.out" + +if [ $errors ]; then + echo -e $errors 'test case(s) failed!' +else + echo -e "all testcases passed." fi -echo "All testcases passed." # That's all Folks! -## \ No newline at end of file +## diff --git a/test/write-video-test.sh b/test/write-video-test.sh new file mode 100755 index 00000000..8207b8e5 --- /dev/null +++ b/test/write-video-test.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# Test driver for write video + +source ./functions.source + +## +# set up output and reference file +out=$(real_path "$testdir/$this.out") +copyTestFile "video/$this.out" + +( cd "$testdir" + + videos=($(copyVideoFiles)) + + # write metadata to videos + runTest exiv2 -M "set Xmp.video.MicroSecPerFrame 64" ${videos[*]} + runTest exiv2 -M "set Xmp.video.MaxDataRate 4096" ${videos[*]} + runTest exiv2 -M "set Xmp.video.FrameCount 2048" ${videos[*]} + runTest exiv2 -M "set Xmp.video.InitialFrames 4" ${videos[*]} + runTest exiv2 -M "set Xmp.video.StreamCount 2" ${videos[*]} + runTest exiv2 -M "set Xmp.video.SuggestedBufferSize 1024" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Width 240" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Height 320" ${videos[*]} + runTest exiv2 -M "set Xmp.video.FileDataRate 128" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Duration 2048" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Codec mjpg" ${videos[*]} + runTest exiv2 -M "set Xmp.video.FrameRate 1024" ${videos[*]} + runTest exiv2 -M "set Xmp.video.VideoQuality 128" ${videos[*]} + runTest exiv2 -M "set Xmp.video.VideoSampleSize 256" ${videos[*]} + runTest exiv2 -M "set Xmp.audio.Codec mpv4" ${videos[*]} + runTest exiv2 -M "set Xmp.audio.SampleRate 32" ${videos[*]} + runTest exiv2 -M "set Xmp.audio.SampleCount 32" ${videos[*]} + runTest exiv2 -M "set Xmp.video.DateUT $date" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Comment Metadata was Edited Using Exiv2" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Language Kannada" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Country India" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Copyright Photographer" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Genre Sample Test Video" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Software Exiv2 0.25" ${videos[*]} + runTest exiv2 -M "set Xmp.video.Junk Its a junk Data" ${videos[*]} + runTest exiv2 -M "set Xmp.video.MediaLanguage English" ${videos[*]} + + for video in ${videos[*]}; do + printf "." >&3 + echo + echo "-----> $video <-----" + echo + echo "Command: exiv2 -u -pa $video" + # run command | ignore binary and no Date nor NumOfColours tags + runTest exiv2 -u -pa "$video" | sed -E -e 's/\d128-\d255/_/g' | grep -a -v -e Date + done + +) 3>&1 2>&1 > "$out" + +echo "." + +# ---------------------------------------------------------------------- +# Result +diffCheck "$out" "$testdir/$datadir/video/$this.out" + +if [ $errors ]; then + echo -e $errors 'test case(s) failed!' +else + echo -e "all testcases passed." +fi + +# That's all Folks! +##