From f0a321dedbf221a84d2a30d821caf91dd595d620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Kov=C3=A1=C5=99?= Date: Tue, 16 Feb 2021 10:10:00 +0100 Subject: [PATCH] [WIP] Base Media File Format --- CMakeLists.txt | 2 +- cmake/config.h.cmake | 4 +- cmake/generateConfigFile.cmake | 2 +- cmake/printSummary.cmake | 2 +- include/exiv2/bmffimage.hpp | 16 +-- include/exiv2/exiv2.hpp | 4 +- src/bmffimage.cpp | 178 ++++++++++++++++++--------------- src/exiv2.cpp | 4 +- src/image.cpp | 8 +- src/version.cpp | 6 ++ 10 files changed, 126 insertions(+), 100 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5cdacfe..8e267d49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ option( EXIV2_ENABLE_WIN_UNICODE "Use Unicode paths (wstring) on Windows" option( EXIV2_ENABLE_WEBREADY "Build webready support into library" OFF ) option( EXIV2_ENABLE_CURL "USE Libcurl for HttpIo (WEBREADY)" OFF ) option( EXIV2_ENABLE_SSH "USE Libssh for SshIo (WEBREADY)" OFF ) -option( EXIV2_ENABLE_ISOBMFF "Build with ISO BMFF support" OFF ) +option( EXIV2_ENABLE_BMFF "Build with BMFF support" OFF ) option( EXIV2_BUILD_SAMPLES "Build sample applications" ON ) option( EXIV2_BUILD_EXIV2_COMMAND "Build exiv2 command-line executable" ON ) diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index cee33398..b633d127 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -18,8 +18,8 @@ // Define if you want translation of program messages to the user's native language #cmakedefine EXV_ENABLE_NLS -// Define if you want ISO BMFF support. -#cmakedefine EXV_ENABLE_ISOBMFF +// Define if you want BMFF support. +#cmakedefine EXV_ENABLE_BMFF // Define if you want video support. #cmakedefine EXV_ENABLE_VIDEO diff --git a/cmake/generateConfigFile.cmake b/cmake/generateConfigFile.cmake index c8ee83f5..fe1cabbd 100644 --- a/cmake/generateConfigFile.cmake +++ b/cmake/generateConfigFile.cmake @@ -7,7 +7,7 @@ if (${EXIV2_ENABLE_WEBREADY}) set(EXV_USE_SSH ${EXIV2_ENABLE_SSH}) set(EXV_USE_CURL ${EXIV2_ENABLE_CURL}) endif() -set(EXV_ENABLE_ISOBMFF ${EXIV2_ENABLE_ISOBMFF}) +set(EXV_ENABLE_BMFF ${EXIV2_ENABLE_BMFF}) set(EXV_ENABLE_VIDEO ${EXIV2_ENABLE_VIDEO}) set(EXV_ENABLE_WEBREADY ${EXIV2_ENABLE_WEBREADY}) set(EXV_HAVE_LENSDATA ${EXIV2_ENABLE_LENSDATA}) diff --git a/cmake/printSummary.cmake b/cmake/printSummary.cmake index fd3a545d..2f3e1fc4 100644 --- a/cmake/printSummary.cmake +++ b/cmake/printSummary.cmake @@ -50,7 +50,7 @@ if ( EXIV2_ENABLE_EXTERNAL_XMP ) else() OptionOutput( "XMP metadata support: " EXIV2_ENABLE_XMP ) endif() -OptionOutput( "Building ISO BMFF support: " EXIV2_ENABLE_ISOBMFF ) +OptionOutput( "Building BMFF support: " EXIV2_ENABLE_BMFF ) OptionOutput( "Native language support: " EXIV2_ENABLE_NLS ) OptionOutput( "Conversion of Windows XP tags: " EXIV2_ENABLE_PRINTUCS2 ) OptionOutput( "Nikon lens database: " EXIV2_ENABLE_LENSDATA ) diff --git a/include/exiv2/bmffimage.hpp b/include/exiv2/bmffimage.hpp index 96f1b7e4..783005c9 100644 --- a/include/exiv2/bmffimage.hpp +++ b/include/exiv2/bmffimage.hpp @@ -30,25 +30,25 @@ // namespace extensions namespace Exiv2 { - EXIV2API bool enableISOBMFF(bool enable = true); + EXIV2API bool enableBMFF(bool enable = true); // ***************************************************************************** // class definitions - // Add ISO Base Media File Format to the supported image formats + // Add Base Media File Format to the supported image formats namespace ImageType { - const int bmff = 15; //!< ISO BMFF (bmff) image type (see class ISOBMFF) + const int bmff = 15; //!< BMFF (bmff) image type (see class BMFF) } /*! - @brief Class to access ISO BMFF images. + @brief Class to access BMFF images. */ class EXIV2API BmffImage : public Image { public: //! @name Creators //@{ /*! - @brief Constructor to open a ISO/IEC BMFF image. Since the + @brief Constructor to open a BMFF image. Since the constructor can not return a result, callers should check the good() method after object construction to determine success or failure. @@ -108,6 +108,8 @@ namespace Exiv2 void doWriteMetadata(BasicIo& outIo); //@} + std::string toAscii(long n); + }; // class BmffImage // ***************************************************************************** @@ -116,12 +118,12 @@ namespace Exiv2 // These could be static private functions on Image subclasses but then // ImageFactory needs to be made a friend. /*! - @brief Create a new ISO BMFF instance and return an auto-pointer to it. + @brief Create a new BMFF 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 newBmffInstance(BasicIo::AutoPtr io, bool create); - //! Check if the file iIo is a ISO BMFF image. + //! Check if the file iIo is a BMFF image. EXIV2API bool isBmffType(BasicIo& iIo, bool advance); } // namespace Exiv2 diff --git a/include/exiv2/exiv2.hpp b/include/exiv2/exiv2.hpp index 1313ad3b..ef9b60af 100644 --- a/include/exiv2/exiv2.hpp +++ b/include/exiv2/exiv2.hpp @@ -46,9 +46,9 @@ #include "exiv2/image.hpp" #include "exiv2/ini.hpp" #include "exiv2/iptc.hpp" -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_BMFF #include "bmffimage.hpp" -#endif// EXV_ENABLE_ISOBMFF +#endif// EXV_ENABLE_BMFF #include "exiv2/jp2image.hpp" #include "exiv2/jpgimage.hpp" #include "exiv2/metadatum.hpp" diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index 0efac584..1894eb0d 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -49,29 +49,23 @@ struct BmffBoxHeader uint32_t type; }; -#if defined(__BIG_ENDIAN__) #define ID(string) ((string[0] << 24) | (string[1] << 16) | (string[2] << 8) | string[3]) -#elif defined(__LITTLE_ENDIAN__) -#define ID(string) (string[0] | (string[1] << 8) | (string[2] << 16) | (string[3] << 24)) -#else -#error "Unknown endian" -#endif -static const uint32_t ftyp = ID("ftyp"); /**< File type box */ -static const uint32_t avif = ID("avif"); /**< AVIF */ -static const uint32_t heic = ID("heic"); /**< HEIF */ -static const uint32_t heif = ID("heif"); /**< HEIF */ -static const uint32_t crx = ID("crx "); /**< Canon CR3 */ -static const uint32_t moov = ID("moov"); /**< Movie */ -static const uint32_t meta = ID("meta"); /**< Metadata */ -static const uint32_t mdat = ID("mdat"); /**< Media data */ -static const uint32_t uuid = ID("uuid"); /**< UUID */ -static const uint32_t dinf = ID("dinf"); /**< Data information */ -static const uint32_t iprp = ID("iprp"); /**< Item properties */ -static const uint32_t ipco = ID("ipco"); /**< Item property container */ -static const uint32_t iinf = ID("iinf"); /**< Item info */ -static const uint32_t iloc = ID("iloc"); /**< Item location */ -static const uint32_t ispe = ID("ispe"); /**< Image spatial extents */ +#define TAG_ftyp ID("ftyp") /**< File type box */ +#define TAG_avif ID("avif") /**< AVIF */ +#define TAG_heic ID("heic") /**< HEIF */ +#define TAG_heif ID("heif") /**< HEIF */ +#define TAG_crx ID("crx ") /**< Canon CR3 */ +#define TAG_moov ID("moov") /**< Movie */ +#define TAG_meta ID("meta") /**< Metadata */ +#define TAG_mdat ID("mdat") /**< Media data */ +#define TAG_uuid ID("uuid") /**< UUID */ +#define TAG_dinf ID("dinf") /**< Data information */ +#define TAG_iprp ID("iprp") /**< Item properties */ +#define TAG_ipco ID("ipco") /**< Item property container */ +#define TAG_iinf ID("iinf") /**< Item info */ +#define TAG_iloc ID("iloc") /**< Item location */ +#define TAG_ispe ID("ispe") /**< Image spatial extents */ // ***************************************************************************** // class member definitions @@ -79,12 +73,12 @@ namespace Exiv2 { static bool enabled = false; - EXIV2API bool enableISOBMFF(bool enable) + EXIV2API bool enableBMFF(bool enable) { -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_BMFF enabled = enable; return true; -#endif // EXV_ENABLE_ISOBMFF +#endif // EXV_ENABLE_BMFF enable = false; // unused return enable; } @@ -94,21 +88,11 @@ namespace Exiv2 { } // BmffImage::BmffImage - static bool isBigEndian() - { - union { - uint32_t i; - char c[4]; - } e = { 0x01000000 }; - - return e.c[0]?true:false; - } - - static std::string toAscii(long n) + std::string BmffImage::toAscii(long n) { const char* p = (const char*) &n; std::string result; - bool bBigEndian = isBigEndian(); + bool bBigEndian = isBigEndianPlatform(); for ( int i = 0 ; i < 4 ; i++) { result += p[ bBigEndian ? i : (3-i) ]; } @@ -135,20 +119,21 @@ namespace Exiv2 bool superBox(uint32_t box) { - return box == moov - || box == dinf - || box == iprp - || box == ipco - || box == meta - || box == iinf - || box == iloc + return box == TAG_moov + || box == TAG_dinf + || box == TAG_iprp + || box == TAG_ipco + || box == TAG_meta + || box == TAG_iinf + || box == TAG_iloc ; } + bool fullBox(uint32_t box) { - return box == meta - || box == iinf - || box == iloc + return box == TAG_meta + || box == TAG_iinf + || box == TAG_iloc ; } @@ -156,14 +141,14 @@ namespace Exiv2 { switch (fileType) { - case avif: + case TAG_avif: return "image/avif"; - case heic: - case heif: + case TAG_heic: + case TAG_heif: return "image/heif"; - case crx: + case TAG_crx: return "image/x-canon-cr3"; default: @@ -174,7 +159,7 @@ namespace Exiv2 void BmffImage::setComment(const std::string& /*comment*/) { // Todo: implement me! - throw(Error(kerInvalidSettingForImage, "Image comment", "ISO BMFF")); + throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); } // BmffImage::setComment void BmffImage::readMetadata() @@ -187,7 +172,7 @@ namespace Exiv2 // Ensure that this is the correct image type if (!isBmffType(*io_, false)) { if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData); - throw Error(kerNotAnImage, "ISO BMFF"); + throw Error(kerNotAnImage, "BMFF"); } long position = 0; @@ -200,58 +185,91 @@ namespace Exiv2 { boxes_check(boxes++, boxem); position = io_->tell(); - uint32_t length = getLong((byte*)&box.length, bigEndian); - uint32_t type = getLong((byte*)&box.type, bigEndian); + box.length = getLong((byte*)&box.length, bigEndian); + box.type = getLong((byte*)&box.type, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES std::cout << "Exiv2::BmffImage::readMetadata: " << "Position: " << position - << " box type: " << toAscii(type) - << " length: " << length + << " box type: " << toAscii(box.type) + << " box length: " << box.length << std::endl; #endif - if (length == 0) return ; + if (box.length == 0) return ; - if (length == 1) + if (box.length == 1) { } - switch (box.type) + if (box.length > 8 && (position + box.length) <= io().size() ) { - case ftyp: + switch (box.type) { - io().read((byte*)&fileType,4); - std::string brand_ = boxName(fileType); + case TAG_ftyp: + { + DataBuf data(box.length); + io().read(data.pData_, data.size_); + fileType = getLong(data.pData_, bigEndian); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: " - << "Brand: " << brand_ - << std::endl; + std::string brand_ = toAscii(fileType); + std::cout << "Exiv2::BmffImage::readMetadata: " + << "Brand: " << brand_ + << std::endl; #endif - break; - } + break; + } - case meta: - { + case TAG_meta: + { + DataBuf data(box.length); + io().read(data.pData_, data.size_); #ifdef EXIV2_DEBUG_MESSAGES - std::cout << "Exiv2::BmffImage::readMetadata: metadata" - << std::endl; + std::cout << "Exiv2::BmffImage::readMetadata: metadata " + << data.size_ << " bytes " << std::endl; + std::cout << std::hex; + for (unsigned i = 0; i < data.size_; i++) + { + std::cout << " " << data.pData_[i]; + } + std::cout << std::dec; + std::cout << std::endl; #endif - break; - } + break; + } + + case TAG_ispe: + { + DataBuf data(box.length); + io().read(data.pData_, data.size_); + + uint32_t flags = getLong(data.pData_, bigEndian); + uint8_t version = (uint8_t) flags >> 24; + flags &= 0x00ffffff; + pixelWidth_ = getLong(data.pData_ + 4, bigEndian); + pixelHeight_ = getLong(data.pData_ + 8, bigEndian); +#ifdef EXIV2_DEBUG_MESSAGES + std::cout << "Exiv2::BmffImage::readMetadata: Image spatial extents " + << "version: " << version + << "flags: " << flags + << std::endl; +#endif + break; + } - default: - { + default: + { #ifdef EXIV2_DEBUG_MESSAGES - std::cout << " box type: " << toAscii(type) - << " length: " << length - << std::endl; + std::cout << " box type: " << toAscii(box.type) + << " box length: " << box.length + << std::endl; #endif - break; + break; + } } } // Move to the next box. - io_->seek(static_cast(position - sizeof(box) + length), BasicIo::beg); + io_->seek(static_cast(position - sizeof(box) + box.length), BasicIo::beg); if (io_->error()) throw Error(kerFailedToReadImageData); } diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 764e5235..f823368b 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -137,8 +137,8 @@ int main(int argc, char* const argv[]) textdomain(EXV_PACKAGE_NAME); #endif -#ifdef EXV_ENABLE_ISOBMFF - Exiv2::enableISOBMFF(); +#ifdef EXV_ENABLE_BMFF + Exiv2::enableBMFF(); #endif // Handle command line arguments diff --git a/src/image.cpp b/src/image.cpp index d5cef016..9267c8e4 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -31,9 +31,9 @@ #include "safe_op.hpp" #include "slice.hpp" -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_BMFF #include "bmffimage.hpp" -#endif// EXV_ENABLE_ISOBMFF +#endif// EXV_ENABLE_BMFF #include "cr2image.hpp" #include "crwimage.hpp" #include "epsimage.hpp" @@ -134,9 +134,9 @@ 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 }, -#ifdef EXV_ENABLE_ISOBMFF +#ifdef EXV_ENABLE_BMFF { ImageType::bmff, newBmffInstance, isBmffType, amRead, amRead, amRead, amNone }, -#endif // EXV_ENABLE_ISOBMFF +#endif // EXV_ENABLE_BMFF #ifdef EXV_ENABLE_VIDEO { ImageType::qtime,newQTimeInstance,isQTimeType,amRead, amNone, amRead, amNone }, { ImageType::riff, newRiffInstance, isRiffType, amRead, amNone, amRead, amNone }, diff --git a/src/version.cpp b/src/version.cpp index ea8d504c..a3b53e08 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -345,6 +345,7 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) int have_unistd =0; int have_unicode_path=0; + int enable_bmff =0; int enable_video =0; int enable_webready =0; int enable_nls =0; @@ -461,6 +462,10 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) have_unicode_path=1; #endif +#ifdef EXV_ENABLE_BMFF + enable_bmff=1; +#endif + #ifdef EXV_ENABLE_VIDEO enable_video=1; #endif @@ -544,6 +549,7 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) output(os,keys,"have_sys_types" ,have_sys_types ); output(os,keys,"have_unistd" ,have_unistd ); output(os,keys,"have_unicode_path" ,have_unicode_path); + output(os,keys,"enable_bmff" ,enable_bmff ); output(os,keys,"enable_video" ,enable_video ); output(os,keys,"enable_webready" ,enable_webready ); output(os,keys,"enable_nls" ,enable_nls );