diff --git a/include/exiv2/asfvideo.hpp b/include/exiv2/asfvideo.hpp
index e41c6602..bf1f222c 100644
--- a/include/exiv2/asfvideo.hpp
+++ b/include/exiv2/asfvideo.hpp
@@ -1,31 +1,7 @@
-// ***************************************************************** -*- C++ -*-
-/*
- * Copyright (C) 2004-2021 Exiv2 authors
- * 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 asfvideo.hpp
- @brief An Image subclass to support ASF video files
- @author Abhinav Badola for GSoC 2012
- mail.abu.to@gmail.com
- @date 08-Aug-12, AB: created
- */
-#ifndef ASFVIDEO_HPP
-#define ASFVIDEO_HPP
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Spec : Advanced Systems Format (ASF) Specification : Revision 01.20.05 :
+// https://exse.eyewated.com/fls/54b3ed95bbfb1a92.pdf
+#pragma once
// *****************************************************************************
#include "exiv2lib_export.h"
@@ -33,10 +9,13 @@
// included header files
#include "image.hpp"
+// *****************************************************************************
+// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
+
/*!
@brief Class to access ASF video files.
*/
@@ -56,11 +35,14 @@ class EXIV2API AsfVideo : public Image {
method to get a temporary reference.
*/
explicit AsfVideo(BasicIo::UniquePtr io);
+ //@}
+ //! @name NOT Implemented
+ //@{
//! Copy constructor
- AsfVideo(const AsfVideo& rhs) = delete;
+ AsfVideo(const AsfVideo&) = delete;
//! Assignment operator
- AsfVideo& operator=(const AsfVideo& rhs) = delete;
+ AsfVideo& operator=(const AsfVideo&) = delete;
//@}
//! @name Manipulators
@@ -71,35 +53,19 @@ class EXIV2API AsfVideo : public Image {
//! @name Accessors
//@{
- std::string mimeType() const override;
+ [[nodiscard]] std::string mimeType() const override;
//@}
private:
- static constexpr size_t GUID_SIZE = 37;
static constexpr size_t CODEC_TYPE_VIDEO = 1;
static constexpr size_t CODEC_TYPE_AUDIO = 2;
- static constexpr size_t BYTE = 1;
- static constexpr size_t WCHAR = 2;
- static constexpr size_t WORD = 2;
- static constexpr size_t DWORD = 4;
- static constexpr size_t QWORD = 8;
- static constexpr size_t GUID = 16;
-
- class AsfObject {
- byte IdBuf_[GUID + 1];
+ class HeaderReader {
+ DataBuf IdBuf_;
uint64_t size_;
uint64_t remaining_size_;
public:
- explicit AsfObject(BasicIo::UniquePtr& io) {
- DataBuf SizeBuf(QWORD + 1);
-
- io->read(IdBuf_, GUID);
- io->read(SizeBuf.data(), QWORD);
-
- size_ = Exiv2::getULongLong(SizeBuf.data(), littleEndian);
- remaining_size_ = size_ - GUID - QWORD;
- }
+ explicit HeaderReader(BasicIo::UniquePtr& io);
[[nodiscard]] uint64_t getSize() const {
return size_;
@@ -109,7 +75,7 @@ class EXIV2API AsfVideo : public Image {
return remaining_size_;
}
- [[nodiscard]] byte* getId() {
+ [[nodiscard]] DataBuf& getId() {
return IdBuf_;
}
};
@@ -158,6 +124,8 @@ class EXIV2API AsfVideo : public Image {
*/
void extendedContentDescription();
+ void DegradableJPEGMedia();
+
/*!
@brief Calculates Aspect Ratio of a video, and stores it in the
respective XMP container.
@@ -168,12 +136,6 @@ class EXIV2API AsfVideo : public Image {
//! Variable to store height and width of a video frame.
uint64_t height_, width_;
- [[nodiscard]] uint64_t readQWORDTag();
- [[nodiscard]] uint32_t readDWORDTag();
- [[nodiscard]] uint16_t readWORDTag();
- [[nodiscard]] std::string readStringWCHAR(uint16_t length);
- [[nodiscard]] std::string readString(uint16_t length);
-
}; // Class AsfVideo
// *****************************************************************************
@@ -191,6 +153,4 @@ EXIV2API Image::UniquePtr newAsfInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a Windows Asf Video.
EXIV2API bool isAsfType(BasicIo& iIo, bool advance);
-} // namespace Exiv2
-
-#endif // #ifndef ASFVIDEO_HPP_
\ No newline at end of file
+} // namespace Exiv2
\ No newline at end of file
diff --git a/include/exiv2/riffvideo.hpp b/include/exiv2/riffvideo.hpp
index f724be53..5c2889dc 100644
--- a/include/exiv2/riffvideo.hpp
+++ b/include/exiv2/riffvideo.hpp
@@ -1,34 +1,10 @@
-// ***************************************************************** -*- C++ -*-
-/*
- * Copyright (C) 2004-2021 Exiv2 authors
- * 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
- * asize_t with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef RIFFVIDEO_HPP
-#define RIFFVIDEO_HPP
-
-// *****************************************************************************
-#include "exiv2lib_export.h"
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
-// included header files
#include "exif.hpp"
+#include "exiv2lib_export.h"
#include "image.hpp"
-// *****************************************************************************
-// namespace extensions
namespace Exiv2 {
// *****************************************************************************
@@ -53,11 +29,14 @@ class EXIV2API RiffVideo : public Image {
method to get a temporary reference.
*/
explicit RiffVideo(BasicIo::UniquePtr io);
+ //@}
+ //! @name NOT Implemented
+ //@{
//! Copy constructor
- RiffVideo(const RiffVideo& rhs) = delete;
+ RiffVideo(const RiffVideo&) = delete;
//! Assignment operator
- RiffVideo& operator=(const RiffVideo& rhs) = delete;
+ RiffVideo& operator=(const RiffVideo&) = delete;
//@}
@@ -71,147 +50,140 @@ class EXIV2API RiffVideo : public Image {
//! @name Accessors
//@{
[[nodiscard]] std::string mimeType() const override;
- [[nodiscard]] static const char* printAudioEncoding(uint64_t i);
//@}
protected:
+ class HeaderReader {
+ std::string id_;
+ uint64_t size_;
+
+ public:
+ explicit HeaderReader(BasicIo::UniquePtr& io);
+
+ [[nodiscard]] uint64_t getSize() const {
+ return size_;
+ }
+
+ [[nodiscard]] std::string& getId() {
+ return id_;
+ }
+ };
+
+ void readList(HeaderReader& header_);
+
+ void readChunk(HeaderReader& header_);
+
+ void decodeBlocks();
+
+ private:
+ bool equal(const std::string& str1, const std::string& str2);
+
/*!
- @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, size_t size);
- /*!
- @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(size_t size);
- /*!
- @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(size_t size);
+ @brief Interpret MainAVIHeader (avih) structure, and save it in the respective XMP container.
+ @param size Size of the data block used to store Tag Information.
+ */
+ void readAviHeader();
+
/*!
- @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(size_t size);
+ @brief Interpret stream header list element (strh), and save it in the respective XMP container.
+ */
+ void readStreamHeader();
+
/*!
- @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(size_t size);
+ @brief Interpret stream header list element (strf), and save it in the respective XMP container.
+ @param size Size of the data block used to store Tag Information.
+ */
+ void readStreamFormat(uint64_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(size_t size);
+ @brief Interpret Additional header data (strd), and save it in the respective XMP container.
+ @param size Size of the data block used to store Tag Information.
+ */
+ void readStreamData(uint64_t 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(size_t size);
+ @brief Interpret stream header list element (strn) , and save it in the respective XMP container.
+ @param size Size of the data block used to store Tag Information.
+ */
+ void StreamName(uint64_t size_);
/*!
- @brief Interpret INFO tag information, and save it
- in the respective XMP container.
- */
- void infoTagsHandler();
+ @brief Interpret INFO List Chunk, and save it in the respective XMP container.
+ @param size Size of the data block used to store Tag Information.
+ */
+ void readInfoListChunk(uint64_t size_);
+
/*!
- @brief Interpret Nikon Tags related to Video information, and
- save it in the respective XMP container.
- */
- void nikonTagsHandler();
+ @brief Interpret Riff Stream Data tag information, and save it in the respective XMP container.
+ The Movi - Lists contain Video, Audio, Subtitle and (secondary) index data. Those can be grouped into rec - Lists.
+ @param size Size of the data block used to store Tag Information.
+ */
+ void readMoviList(uint64_t size_);
/*!
- @brief Interpret OpenDML tag information, and save it
- in the respective XMP container.
- */
- void odmlTagsHandler();
- //! @brief Skips Particular Blocks of Metadata List.
- void skipListData();
+ @brief Interpret Video Properties Header chunk, and save it in the respective XMP container.
+ The video properties header identifies video signal properties associated with a digital video stream in an AVI file
+ @param size Size of the data block used to store Tag Information.
+ */
+ void readVPRPChunk(uint64_t size_);
/*!
- @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(size_t size, int i = 0);
+ @brief Interpret Riff INdex Chunk, and save it in the respective XMP container.
+ @param size Size of the data block used to store Tag Information.
+ */
+ void readIndexChunk(uint64_t size_);
/*!
- @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.
- */
- [[nodiscard]] static double returnSampleRate(Exiv2::DataBuf& buf, size_t divisor = 1);
+ @brief Interpret Riff Stream Chunk, and save it in the respective XMP container.
+ @param size Size of the data block used to store Tag Information.
+ */
+ void readDataChunk(uint64_t size_);
/*!
- @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(size_t width = 1, size_t height = 1);
+ @brief Interpret Junk Chunk and save it in the respective XMP container.
+ @param size Size of the data block used to store Tag Information.
+ */
+ void readJunk(uint64_t size_);
+
+ std::string getStreamType(uint32_t stream);
/*!
- @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.
- */
+ @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, size_t frame_count);
- [[nodiscard]] static bool equalsRiffTag(Exiv2::DataBuf& buf, const char* str);
-
- static void copyTagValue(DataBuf& buf_dest, DataBuf& buf_src, size_t index = RIFF_TAG_SIZE);
+ /*!
+ @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(size_t width, size_t height);
- private:
- static constexpr size_t RIFF_TAG_SIZE = 0x4;
- static constexpr auto RIFF_CHUNK_HEADER_ICCP = "ICCP";
- static constexpr auto RIFF_CHUNK_HEADER_EXIF = "EXIF";
- static constexpr auto RIFF_CHUNK_HEADER_XMP = "XMP ";
+ static constexpr auto CHUNK_HEADER_ICCP = "ICCP";
+ static constexpr auto CHUNK_HEADER_EXIF = "EXIF";
+ static constexpr auto CHUNK_HEADER_XMP = "XMP ";
/* Chunk header names */
- static constexpr auto RIFF_CHUNK_ID_MOVI = "MOVI";
- static constexpr auto RIFF_CHUNK_ID_DATA = "DATA";
- static constexpr auto RIFF_CHUNK_ID_HDRL = "HDRL";
- static constexpr auto RIFF_CHUNK_ID_STRL = "STRL";
- static constexpr auto RIFF_CHUNK_ID_LIST = "LIST";
- static constexpr auto RIFF_CHUNK_ID_JUNK = "JUNK";
- static constexpr auto RIFF_CHUNK_ID_AVIH = "AVIH";
- static constexpr auto RIFF_CHUNK_ID_STRH = "STRH";
- static constexpr auto RIFF_CHUNK_ID_STRF = "STRF";
- static constexpr auto RIFF_CHUNK_ID_FMT = "FMT ";
- static constexpr auto RIFF_CHUNK_ID_STRN = "STRN";
- static constexpr auto RIFF_CHUNK_ID_STRD = "STRD";
- static constexpr auto RIFF_CHUNK_ID_IDIT = "IDIT";
- static constexpr auto RIFF_CHUNK_ID_INFO = "INFO";
- static constexpr auto RIFF_CHUNK_ID_NCDT = "NCDT";
- static constexpr auto RIFF_CHUNK_ID_ODML = "ODML";
-
- //! Variable to check the end of metadata traversing.
- bool continueTraversing_;
- //! Variable which stores current stream being processsed.
+ static constexpr auto CHUNK_ID_MOVI = "MOVI";
+ static constexpr auto CHUNK_ID_DATA = "DATA";
+ static constexpr auto CHUNK_ID_HDRL = "HDRL";
+ static constexpr auto CHUNK_ID_STRL = "STRL";
+ static constexpr auto CHUNK_ID_LIST = "LIST";
+ static constexpr auto CHUNK_ID_JUNK = "JUNK";
+ static constexpr auto CHUNK_ID_AVIH = "AVIH";
+ static constexpr auto CHUNK_ID_STRH = "STRH";
+ static constexpr auto CHUNK_ID_STRF = "STRF";
+ static constexpr auto CHUNK_ID_FMT = "FMT ";
+ static constexpr auto CHUNK_ID_STRN = "STRN";
+ static constexpr auto CHUNK_ID_STRD = "STRD";
+ static constexpr auto CHUNK_ID_IDIT = "IDIT";
+ static constexpr auto CHUNK_ID_INFO = "INFO";
+ static constexpr auto CHUNK_ID_NCDT = "NCDT";
+ static constexpr auto CHUNK_ID_ODML = "ODML";
+ static constexpr auto CHUNK_ID_VPRP = "VPRP";
+ static constexpr auto CHUNK_ID_IDX1 = "IDX1";
+
int streamType_;
}; // 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.
-/*!
+/*
@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.
@@ -222,5 +194,3 @@ EXIV2API Image::UniquePtr newRiffInstance(BasicIo::UniquePtr io, bool create);
EXIV2API bool isRiffType(BasicIo& iIo, bool advance);
} // namespace Exiv2
-
-#endif // RIFFVIDEO_HPP
diff --git a/src/asfvideo.cpp b/src/asfvideo.cpp
index cd0b6d10..22505aceb 100644
--- a/src/asfvideo.cpp
+++ b/src/asfvideo.cpp
@@ -1,63 +1,26 @@
-// ***************************************************************** -*- C++ -*-
-/*
- * Copyright (C) 2004-2021 Exiv2 authors
- * 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: asfvideo.cpp
- Author(s): Abhinav Badola for GSoC 2012 (AB)
- History: 08-Aug-12, AB: created
- Credits: See header file
- Spec: https://exse.eyewated.com/fls/54b3ed95bbfb1a92.pdf
- */
-// *****************************************************************************
+// SPDX-License-Identifier: GPL-2.0-or-later
// included header files
-#include
-#include "config.h"
-
#include "asfvideo.hpp"
+#include
#include "basicio.hpp"
-#include "convert.hpp"
+#include "config.h"
#include "error.hpp"
#include "futils.hpp"
#include "helper_functions.hpp"
-#include "tags.hpp"
-#include "tags_int.hpp"
-#include "types.hpp"
-
-// + standard includes
-#include
-#include
-#include
-
// *****************************************************************************
// class member definitions
namespace Exiv2::Internal {
/*!
- TagVocabulary Look-up list for ASF Type Video Files
- Associates the GUID of a TagVocabulary with its TagVocabulary Name(i.e. Human Readable Form)
+ Look-up list for ASF Type Video Files
+ Associates the GUID with its Name(i.e. Human Readable Form)
Tags have been diferentiated into Various Categories.
- The categories have been listed above the TagVocabulary Groups
+ The categories have been listed above Groups
see :
- https://fr.wikipedia.org/wiki/Advanced_Systems_Format
- https://exse.eyewated.com/fls/54b3ed95bbfb1a92.pdf
*/
-constexpr const TagVocabulary GUIDReferenceTags[] = {
+const std::map GUIDReferenceTags = {
/// Top-level ASF object GUIDS
{"75B22630-668E-11CF-A6D9-00AA0062CE6C", "Header"},
{"75B22636-668E-11CF-A6D9-00AA0062CE6C", "Data"},
@@ -149,52 +112,55 @@ constexpr const TagVocabulary GUIDReferenceTags[] = {
{"6698B84E-0AFA-4330-AEB2-1C0A98D7A44D", "Payload_Extension_System_Encryption_Sample_ID"},
{"00E1AF06-7BEC-11D1-A582-00C04FC29CFB", "Payload_Extension_System_Degradable_JPEG"}};
-/*!
- @brief Function used to check equality of two Tags (ignores case).
- @param str1 char* Pointer to First TagVocabulary
- @param str2 char* Pointer to Second TagVocabulary
- @return Returns true if both are equal.
- */
-bool compareTag(const char* str1, const char* str2) {
- if (strlen(str1) != strlen(str2))
- return false;
-
- for (uint64_t i = 0; i < strlen(str1); ++i)
- if (tolower(str1[i]) != tolower(str2[i]))
- return false;
-
- return true;
-}
-
/*!
@brief Function used to calculate GUID, Tags comprises of 16 bytes.
The Buffer contains the TagVocabulary in Binary Form. The information is then
parsed into a character array GUID.
+ https://fr.wikipedia.org/wiki/Globally_unique_identifier
*/
-void getGUID(byte buf[], char GUID[]) {
- int i;
- for (i = 0; i < 4; ++i) {
- GUID[(3 - i) * 2] = Util::returnHEX(buf[i] / 0x10);
- GUID[(3 - i) * 2 + 1] = Util::returnHEX(buf[i] % 0x10);
- }
- for (i = 4; i < 6; ++i) {
- GUID[(9 - i) * 2 + 1] = Util::returnHEX(buf[i] / 0x10);
- GUID[(9 - i) * 2 + 2] = Util::returnHEX(buf[i] % 0x10);
- }
- for (i = 6; i < 8; ++i) {
- GUID[(14 - i) * 2] = Util::returnHEX(buf[i] / 0x10);
- GUID[(14 - i) * 2 + 1] = Util::returnHEX(buf[i] % 0x10);
- }
- for (i = 8; i < 10; ++i) {
- GUID[i * 2 + 3] = Util::returnHEX(buf[i] / 0x10);
- GUID[i * 2 + 4] = Util::returnHEX(buf[i] % 0x10);
- }
- for (i = 10; i < 16; ++i) {
- GUID[i * 2 + 4] = Util::returnHEX(buf[i] / 0x10);
- GUID[i * 2 + 5] = Util::returnHEX(buf[i] % 0x10);
+std::string getGUID(DataBuf& buf) {
+ std::string GUID(36, '-');
+ if (buf.size() >= 16) {
+ GUID[0] = returnHex(buf.data()[3] / 0x10);
+ GUID[1] = returnHex(buf.data()[3] % 0x10);
+ GUID[2] = returnHex(buf.data()[2] / 0x10);
+ GUID[3] = returnHex(buf.data()[2] % 0x10);
+ GUID[4] = returnHex(buf.data()[1] / 0x10);
+ GUID[5] = returnHex(buf.data()[1] % 0x10);
+ GUID[6] = returnHex(buf.data()[0] / 0x10);
+ GUID[7] = returnHex(buf.data()[0] % 0x10);
+
+ GUID[9] = returnHex(buf.data()[5] / 0x10);
+ GUID[10] = returnHex(buf.data()[5] % 0x10);
+ GUID[11] = returnHex(buf.data()[4] / 0x10);
+ GUID[12] = returnHex(buf.data()[4] % 0x10);
+
+ GUID[14] = returnHex(buf.data()[7] / 0x10);
+ GUID[15] = returnHex(buf.data()[7] % 0x10);
+ GUID[16] = returnHex(buf.data()[6] / 0x10);
+ GUID[17] = returnHex(buf.data()[6] % 0x10);
+
+ GUID[19] = returnHex(buf.data()[8] / 0x10);
+ GUID[20] = returnHex(buf.data()[8] % 0x10);
+ GUID[21] = returnHex(buf.data()[9] / 0x10);
+ GUID[22] = returnHex(buf.data()[9] % 0x10);
+
+ GUID[24] = returnHex(buf.data()[10] / 0x10);
+ GUID[25] = returnHex(buf.data()[10] % 0x10);
+ GUID[26] = returnHex(buf.data()[11] / 0x10);
+ GUID[27] = returnHex(buf.data()[11] % 0x10);
+ GUID[28] = returnHex(buf.data()[12] / 0x10);
+ GUID[29] = returnHex(buf.data()[12] % 0x10);
+ GUID[30] = returnHex(buf.data()[13] / 0x10);
+ GUID[31] = returnHex(buf.data()[13] % 0x10);
+ GUID[32] = returnHex(buf.data()[14] / 0x10);
+ GUID[33] = returnHex(buf.data()[14] % 0x10);
+ GUID[34] = returnHex(buf.data()[15] / 0x10);
+ GUID[35] = returnHex(buf.data()[15] % 0x10);
}
- GUID[36] = '\0';
- GUID[8] = GUID[13] = GUID[18] = GUID[23] = '-';
+
+ // Example of output 399595EC-8667-4E2D-8FDB-98814CE76C1E
+ return GUID;
}
/*!
@@ -203,7 +169,7 @@ void getGUID(byte buf[], char GUID[]) {
@param buf Exiv2 byte buffer
@return Returns true if the buffer data is equivalent to Header GUID.
*/
-bool isASFType(byte buf[]) {
+bool isASFType(const byte buf[]) {
return buf[0] == 0x30 && buf[1] == 0x26 && buf[2] == 0xb2 && buf[3] == 0x75 && buf[4] == 0x8e && buf[5] == 0x66 &&
buf[6] == 0xcf && buf[7] == 0x11 && buf[8] == 0xa6 && buf[9] == 0xd9 && buf[10] == 0x00 && buf[11] == 0xaa &&
buf[12] == 0x00 && buf[13] == 0x62 && buf[14] == 0xce && buf[15] == 0x6c;
@@ -249,57 +215,66 @@ void AsfVideo::readMetadata() {
aspectRatio();
} // AsfVideo::readMetadata
-void AsfVideo::decodeBlock() {
- AsfObject obj(io_);
+AsfVideo::HeaderReader::HeaderReader(BasicIo::UniquePtr& io) : IdBuf_(GUID) {
+ if (io->size() >= io->tell() + QWORD + QWORD) {
+ IdBuf_ = io->read(GUID);
+
+ size_ = readQWORDTag(io);
+ if (size_ >= GUID + QWORD)
+ remaining_size_ = size_ - GUID - QWORD;
+ }
+}
- char guid[GUID_SIZE] = "";
- getGUID(obj.getId(), guid);
+void AsfVideo::decodeBlock() {
+ HeaderReader header(io_);
+ std::string guid = getGUID(header.getId());
- auto tv = find(GUIDReferenceTags, guid);
- if (tv) {
- if (compareTag(exvGettext(tv->label_), "Header")) {
+ auto tv = GUIDReferenceTags.find(guid);
+ if (tv != GUIDReferenceTags.end()) {
+ if (tv->second == "Header") {
DataBuf nbHeadersBuf(DWORD + 1);
io_->read(nbHeadersBuf.data(), DWORD);
uint32_t nb_headers = Exiv2::getULong(nbHeadersBuf.data(), littleEndian);
- DataBuf reserved(BYTE + 1);
- io_->read(reserved.data(), BYTE);
- io_->read(reserved.data(), BYTE);
+ io_->seekOrThrow(io_->tell() + BYTE * 2, BasicIo::beg,
+ ErrorCode::kerFailedToReadImageData); // skip two reserved tags
for (uint32_t i = 0; i < nb_headers; i++) {
- AsfObject obj(io_);
- char guid[GUID_SIZE] = "";
- getGUID(obj.getId(), guid);
- auto tag = find(GUIDReferenceTags, guid);
- if (tag) {
- if (compareTag(exvGettext(tag->label_), "File_Properties"))
+ HeaderReader others(io_);
+ auto guid = getGUID(others.getId());
+ auto tag = GUIDReferenceTags.find(guid);
+ if (tag != GUIDReferenceTags.end()) {
+ if (tag->second == "File_Properties")
fileProperties();
- else if (compareTag(exvGettext(tag->label_), "Stream_Properties"))
+ else if (tag->second == "Stream_Properties")
streamProperties();
- else if (compareTag(exvGettext(tag->label_), "Header_Extension"))
+ else if (tag->second == "Header_Extension")
headerExtension();
- else if (compareTag(exvGettext(tag->label_), "Codec_List"))
+ else if (tag->second == "Codec_List")
codecList();
- else if (compareTag(exvGettext(tag->label_), "Extended_Content_Description"))
+ else if (tag->second == "Extended_Content_Description")
extendedContentDescription();
- else if (compareTag(exvGettext(tag->label_), "Content_Description"))
+ else if (tag->second == "Content_Description")
contentDescription();
- else if (compareTag(exvGettext(tag->label_), "Extended_Stream_Properties"))
+ else if (tag->second == "Extended_Stream_Properties")
extendedStreamProperties();
- else
- io_->seek(io_->tell() + obj.getRemainingSize(), BasicIo::beg);
+ else if (tag->second == "Degradable_JPEG_Media") {
+ DegradableJPEGMedia();
+ } else
+ io_->seekOrThrow(io_->tell() + others.getRemainingSize(), BasicIo::beg,
+ ErrorCode::kerFailedToReadImageData);
} else
- io_->seek(io_->tell() + obj.getRemainingSize(), BasicIo::beg);
+ io_->seekOrThrow(io_->tell() + others.getRemainingSize(), BasicIo::beg, ErrorCode::kerFailedToReadImageData);
}
} else
- io_->seek(io_->tell() + obj.getRemainingSize(), BasicIo::beg);
+ io_->seekOrThrow(io_->tell() + header.getRemainingSize(), BasicIo::beg, ErrorCode::kerFailedToReadImageData);
} else
- io_->seek(io_->tell() + obj.getRemainingSize(), BasicIo::beg);
+ io_->seekOrThrow(io_->tell() + header.getRemainingSize(), BasicIo::beg, ErrorCode::kerFailedToReadImageData);
} // AsfVideo::decodeBlock
void AsfVideo::extendedStreamProperties() {
- xmpData()["Xmp.video.StartTimecode"] = readQWORDTag(); // Start Time
- xmpData()["Xmp.video.EndTimecode"] = readWORDTag(); // End Time
+ xmpData()["Xmp.video.StartTimecode"] = readQWORDTag(io_); // Start Time
+ xmpData()["Xmp.video.EndTimecode"] = readWORDTag(io_); // End Time
io_->seek(io_->tell() + DWORD, BasicIo::beg); // ignore Data Bitrate
io_->seek(io_->tell() + DWORD, BasicIo::beg); // ignore Buffer Size
@@ -312,13 +287,13 @@ void AsfVideo::extendedStreamProperties() {
io_->seek(io_->tell() + WORD, BasicIo::beg); // ignore Flags Stream Number
io_->seek(io_->tell() + WORD, BasicIo::beg); // ignore Stream Language ID Index
- xmpData()["Xmp.video.FrameRate"] = readWORDTag(); // Average Time Per Frame
- uint16_t stream_name_count = readWORDTag();
- uint16_t payload_ext_sys_count = readWORDTag();
+ xmpData()["Xmp.video.FrameRate"] = readWORDTag(io_); // Average Time Per Frame
+ uint16_t stream_name_count = readWORDTag(io_);
+ uint16_t payload_ext_sys_count = readWORDTag(io_);
for (uint16_t i = 0; i < stream_name_count; i++) {
io_->seek(io_->tell() + WORD, BasicIo::beg); // ignore Language ID Index
- uint16_t stream_length = readWORDTag();
+ uint16_t stream_length = readWORDTag(io_);
if (stream_length)
io_->seek(io_->tell() + stream_length, BasicIo::beg); // ignore Stream name
}
@@ -326,38 +301,51 @@ void AsfVideo::extendedStreamProperties() {
for (uint16_t i = 0; i < payload_ext_sys_count; i++) {
io_->seek(io_->tell() + GUID, BasicIo::beg); // ignore Extension System ID
io_->seek(io_->tell() + WORD, BasicIo::beg); // ignore Extension Data Size
- uint16_t ext_sys_info_length = readWORDTag();
+ uint16_t ext_sys_info_length = readWORDTag(io_);
if (ext_sys_info_length)
io_->seek(io_->tell() + ext_sys_info_length, BasicIo::beg); // ignore Extension System Info
}
} // AsfVideo::extendedStreamProperties
+void AsfVideo::DegradableJPEGMedia() {
+ uint32_t width = readDWORDTag(io_);
+ width_ = width;
+ xmpData_["Xmp.video.Width"] = width;
+
+ uint32_t height = readDWORDTag(io_);
+ height_ = height;
+ xmpData_["Xmp.video.Height"] = height;
+
+ io_->seek(io_->tell() + WORD * 3 /*3 Reserved*/, BasicIo::beg);
+
+ uint32_t interchange_data_length = readWORDTag(io_);
+ io_->seek(io_->tell() + interchange_data_length /*Interchange data*/, BasicIo::beg);
+}
void AsfVideo::streamProperties() {
- byte streamTypedBuf[GUID];
- io_->read(streamTypedBuf,GUID);
- char stream_type[GUID_SIZE] = "";
- getGUID(streamTypedBuf, stream_type);
+ DataBuf streamTypedBuf = io_->read(GUID);
+
+ auto stream_type = getGUID(streamTypedBuf);
enum streamTypeInfo { Audio = 1, Video = 2 };
int stream = 0;
- auto tag_stream_type = find(GUIDReferenceTags, stream_type);
- if (tag_stream_type) {
- if (compareTag(exvGettext(tag_stream_type->label_), "Audio_Media"))
+ auto tag_stream_type = GUIDReferenceTags.find(stream_type);
+ if (tag_stream_type != GUIDReferenceTags.end()) {
+ if (tag_stream_type->second == "Audio_Media")
stream = Audio;
- else if (compareTag(exvGettext(tag_stream_type->label_), "Video_Media"))
+ else if (tag_stream_type->second == "Video_Media")
stream = Video;
io_->seek(io_->tell() + GUID, BasicIo::beg); // ignore Error Correction Type
- uint64_t time_offset = readQWORDTag();
+ uint64_t time_offset = readQWORDTag(io_);
if (stream == Video)
xmpData()["Xmp.video.TimeOffset"] = time_offset;
else if (stream == Audio)
xmpData()["Xmp.audio.TimeOffset"] = time_offset;
- auto specific_data_length = readDWORDTag();
- auto correction_data_length = readDWORDTag();
+ auto specific_data_length = readDWORDTag(io_);
+ auto correction_data_length = readDWORDTag(io_);
io_->seek(io_->tell() + WORD /*Flags*/ + DWORD /*Reserved*/ + specific_data_length + correction_data_length,
BasicIo::beg);
@@ -367,62 +355,62 @@ void AsfVideo::streamProperties() {
void AsfVideo::codecList() {
io_->seek(io_->tell() + GUID /*reserved*/, BasicIo::beg);
- auto entries_count = readDWORDTag();
+ auto entries_count = readDWORDTag(io_);
for (uint32_t i = 0; i < entries_count; i++) {
- uint16_t codec_type = readWORDTag() * 2;
+ uint16_t codec_type = readWORDTag(io_) * 2;
std::string codec = (codec_type == 1) ? "Xmp.video" : "Xmp.audio";
- uint16_t codec_name_length = readWORDTag() * 2;
+ uint16_t codec_name_length = readWORDTag(io_) * 2;
if (codec_name_length)
- xmpData()[codec + std::string(".CodecName")] = readStringWCHAR(codec_name_length);
+ xmpData()[codec + std::string(".CodecName")] = readStringWcharTag(io_, codec_name_length);
- uint16_t codec_desc_length = readWORDTag();
+ uint16_t codec_desc_length = readWORDTag(io_);
if (codec_desc_length)
- xmpData()[codec + std::string(".CodecDescription")] = readStringWCHAR(codec_desc_length);
+ xmpData()[codec + std::string(".CodecDescription")] = readStringWcharTag(io_, codec_desc_length);
- uint16_t codec_info_length = readWORDTag();
+ uint16_t codec_info_length = readWORDTag(io_);
if (codec_info_length)
- xmpData()[codec + std::string(".CodecInfo")] = readString(codec_info_length);
+ xmpData()[codec + std::string(".CodecInfo")] = readStringTag(io_, codec_info_length);
}
} // AsfVideo::codecList
void AsfVideo::headerExtension() {
io_->seek(io_->tell() + GUID /*reserved1*/ + WORD /*Reserved2*/, BasicIo::beg);
- auto header_ext_data_length = readDWORDTag();
+ auto header_ext_data_length = readDWORDTag(io_);
io_->seek(io_->tell() + header_ext_data_length, BasicIo::beg);
} // AsfVideo::headerExtension
void AsfVideo::extendedContentDescription() {
- uint16_t content_descriptor_count = readWORDTag();
+ uint16_t content_descriptor_count = readWORDTag(io_);
std::string value;
for (uint16_t i = 0; i < content_descriptor_count; i++) {
- uint16_t descriptor_name_length = readWORDTag();
+ uint16_t descriptor_name_length = readWORDTag(io_);
if (descriptor_name_length)
- value += readStringWCHAR(descriptor_name_length); // Descriptor Name
+ value += readStringWcharTag(io_, descriptor_name_length); // Descriptor Name
- uint16_t descriptor_value_data_type = readWORDTag();
- uint16_t descriptor_value_length = readWORDTag();
+ uint16_t descriptor_value_data_type = readWORDTag(io_);
+ uint16_t descriptor_value_length = readWORDTag(io_);
if (descriptor_value_length) {
// Descriptor Value
switch (descriptor_value_data_type) {
case 0 /*Unicode string */:
- value += std::string(": ") + readStringWCHAR(descriptor_value_length);
+ value += std::string(": ") + readStringWcharTag(io_, descriptor_value_length);
break;
case 1 /*BYTE array */:
- value += std::string(": ") + readString(descriptor_value_length);
+ value += std::string(": ") + readStringTag(io_, descriptor_value_length);
break;
case 2 /*BOOL*/:
- value += std::string(": ") + std::to_string(readWORDTag());
+ value += std::string(": ") + std::to_string(readWORDTag(io_));
break;
case 3 /*DWORD */:
- value += std::string(": ") + std::to_string(readDWORDTag());
+ value += std::string(": ") + std::to_string(readDWORDTag(io_));
break;
case 4 /*QWORD */:
- value += std::string(": ") + std::to_string(readQWORDTag());
+ value += std::string(": ") + std::to_string(readQWORDTag(io_));
break;
case 5 /*WORD*/:
- value += std::string(": ") + std::to_string(readWORDTag());
+ value += std::string(": ") + std::to_string(readWORDTag(io_));
;
break;
}
@@ -434,82 +422,48 @@ void AsfVideo::extendedContentDescription() {
} // AsfVideo::extendedContentDescription
void AsfVideo::contentDescription() {
- uint16_t title_length = readWORDTag();
- uint16_t author_length = readWORDTag();
- uint16_t copyright_length = readWORDTag();
- uint16_t desc_length = readWORDTag();
- uint16_t rating_length = readWORDTag();
+ uint16_t title_length = readWORDTag(io_);
+ uint16_t author_length = readWORDTag(io_);
+ uint16_t copyright_length = readWORDTag(io_);
+ uint16_t desc_length = readWORDTag(io_);
+ uint16_t rating_length = readWORDTag(io_);
if (title_length)
- xmpData()["Xmp.video.Title"] = readStringWCHAR(title_length);
+ xmpData()["Xmp.video.Title"] = readStringWcharTag(io_, title_length);
if (author_length)
- xmpData()["Xmp.video.Author"] = readStringWCHAR(author_length);
+ xmpData()["Xmp.video.Author"] = readStringWcharTag(io_, author_length);
if (copyright_length)
- xmpData()["Xmp.video.Copyright"] = readStringWCHAR(copyright_length);
+ xmpData()["Xmp.video.Copyright"] = readStringWcharTag(io_, copyright_length);
if (desc_length)
- xmpData()["Xmp.video.Description"] = readStringWCHAR(desc_length);
+ xmpData()["Xmp.video.Description"] = readStringWcharTag(io_, desc_length);
if (rating_length)
- xmpData()["Xmp.video.Rating"] = readStringWCHAR(rating_length);
+ xmpData()["Xmp.video.Rating"] = readStringWcharTag(io_, rating_length);
} // AsfVideo::extendedContentDescription
-uint64_t AsfVideo::readQWORDTag() {
- DataBuf FieldBuf(QWORD);
- io_->read(FieldBuf.data(), QWORD);
- uint64_t field = Util::getUint64_t(FieldBuf);
- return field;
-}
-
-uint32_t AsfVideo::readDWORDTag() {
- DataBuf FieldBuf(DWORD);
- io_->read(FieldBuf.data(), DWORD);
- uint32_t field = Exiv2::getULong(FieldBuf.data(), littleEndian);
- return field;
-}
-
-uint16_t AsfVideo::readWORDTag() {
- DataBuf FieldBuf(WORD);
- io_->read(FieldBuf.data(), WORD);
- uint16_t field = Exiv2::getUShort(FieldBuf.data(), littleEndian);
- return field;
-}
-
-std::string AsfVideo::readStringWCHAR(uint16_t length) {
- DataBuf FieldBuf(length);
- io_->read(FieldBuf.data(), length);
- return Util::toString16(FieldBuf);
-}
-
-std::string AsfVideo::readString(uint16_t length) {
- DataBuf FieldBuf(length);
- io_->read(FieldBuf.data(), length);
- return Exiv2::toString(FieldBuf.data());
-}
-
void AsfVideo::fileProperties() {
- byte FileIddBuf[GUID];
- io_->read(FileIddBuf, GUID);
- char fileId[GUID_SIZE] = "";
- getGUID(FileIddBuf, fileId);
- xmpData()["Xmp.video.FileID"] = fileId;
- xmpData()["Xmp.video.FileLength"] = readQWORDTag();
- xmpData()["Xmp.video.CreationDate"] = readQWORDTag();
- xmpData()["Xmp.video.DataPackets"] = readQWORDTag();
- xmpData()["Xmp.video.Duration"] = readQWORDTag();
- xmpData()["Xmp.video.SendDuration"] = readQWORDTag();
- xmpData()["Xmp.video.Preroll"] = readQWORDTag();
+ DataBuf FileIddBuf = io_->read(GUID);
+ xmpData()["Xmp.video.FileID"] = getGUID(FileIddBuf);
+ xmpData()["Xmp.video.FileLength"] = readQWORDTag(io_);
+ xmpData()["Xmp.video.CreationDate"] = readQWORDTag(io_);
+ xmpData()["Xmp.video.DataPackets"] = readQWORDTag(io_);
+ xmpData()["Xmp.video.Duration"] = readQWORDTag(io_);
+ xmpData()["Xmp.video.SendDuration"] = readQWORDTag(io_);
+ xmpData()["Xmp.video.Preroll"] = readQWORDTag(io_);
io_->seek(io_->tell() + DWORD + DWORD + DWORD, BasicIo::beg);
- xmpData()["Xmp.video.MaxBitRate"] = readDWORDTag();
+ xmpData()["Xmp.video.MaxBitRate"] = readDWORDTag(io_);
} // AsfVideo::fileProperties
void AsfVideo::aspectRatio() {
// TODO - Make a better unified method to handle all cases of Aspect Ratio
+ if (!height_)
+ return;
double aspectRatio = static_cast(width_) / height_;
aspectRatio = floor(aspectRatio * 10) / 10;
xmpData()["Xmp.video.AspectRatio"] = aspectRatio;
@@ -553,9 +507,8 @@ Image::UniquePtr newAsfInstance(BasicIo::UniquePtr io, bool /*create*/) {
}
bool isAsfType(BasicIo& iIo, bool advance) {
- const int32_t len = 16;
- byte buf[len];
- iIo.read(buf, len);
+ byte buf[GUID];
+ iIo.read(buf, GUID);
if (iIo.error() || iIo.eof()) {
return false;
diff --git a/src/helper_functions.cpp b/src/helper_functions.cpp
index 2873cdc8..b378828f 100644
--- a/src/helper_functions.cpp
+++ b/src/helper_functions.cpp
@@ -4,6 +4,7 @@
#include
#include
+#include "enforce.hpp"
std::string string_from_unterminated(const char* data, size_t data_length) {
if (data_length == 0) {
@@ -13,8 +14,8 @@ std::string string_from_unterminated(const char* data, size_t data_length) {
return {data, StringLength};
}
-namespace Util {
-char returnHEX(int n) {
+namespace Exiv2 {
+char returnHex(int n) {
if (n >= 0 && n <= 9)
return static_cast(n + 48);
return static_cast(n + 55);
@@ -36,12 +37,34 @@ std::string toString16(Exiv2::DataBuf& buf) {
return os.str();
}
-uint64_t getUint64_t(Exiv2::DataBuf& buf) {
- uint64_t temp = 0;
+uint64_t readQWORDTag(BasicIo::UniquePtr& io) {
+ enforce(QWORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
+ DataBuf FieldBuf = io->read(QWORD);
+ return FieldBuf.read_uint64(0, littleEndian);
+}
- for (int i = 0; i < 8; ++i) {
- temp = temp + static_cast(buf.data()[i] * (pow(static_cast(256), i)));
- }
- return temp;
+uint32_t readDWORDTag(BasicIo::UniquePtr& io) {
+ enforce(DWORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
+ DataBuf FieldBuf = io->read(DWORD);
+ return FieldBuf.read_uint32(0, littleEndian);
}
-} // namespace Util
+
+uint16_t readWORDTag(BasicIo::UniquePtr& io) {
+ enforce(WORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
+ DataBuf FieldBuf = io->read(WORD);
+ return FieldBuf.read_uint16(0, littleEndian);
+}
+
+std::string readStringWcharTag(BasicIo::UniquePtr& io, uint16_t length) {
+ enforce(length <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
+ DataBuf FieldBuf = io->read(length);
+ return toString16(FieldBuf);
+}
+
+std::string readStringTag(BasicIo::UniquePtr& io, uint16_t length) {
+ enforce(length <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
+ DataBuf FieldBuf = io->read(length);
+ return Exiv2::toString(FieldBuf.data());
+}
+
+} // namespace Exiv2
diff --git a/src/helper_functions.hpp b/src/helper_functions.hpp
index 34562ee9..0d530e71 100644
--- a/src/helper_functions.hpp
+++ b/src/helper_functions.hpp
@@ -5,6 +5,7 @@
#include
#include "types.hpp"
+#include "basicio.hpp"
/*!
@brief Convert a (potentially not null terminated) array into a
std::string.
@@ -22,14 +23,14 @@
*/
std::string string_from_unterminated(const char* data, size_t data_length);
-namespace Util {
+namespace Exiv2 {
/*!
@brief Function used to convert a decimal number to its Hexadecimal
equivalent, then parsed into a character
@param n Integer which is to be parsed as Hexadecimal character
@return Return a Hexadecimal number, in character
*/
-char returnHEX(int n);
+char returnHex(int n);
/*!
@brief Function used to read data from data buffer, reads 16-bit character
@@ -37,9 +38,27 @@ char returnHEX(int n);
@param buf Exiv2 data buffer, which stores the information
@return Returns std::string object .
*/
+
+
+static constexpr size_t BYTE = 0x1;
+static constexpr size_t WCHAR = 0x2;
+static constexpr size_t WORD = 0X2;
+static constexpr size_t DWORD = 0x4;
+static constexpr size_t QWORD = 0x8;
+static constexpr size_t GUID = 0x10;
+
std::string toString16(Exiv2::DataBuf& buf);
-//! Function used to convert buffer data into 64-bit Integer, information stored in littleEndian format
-uint64_t getUint64_t(Exiv2::DataBuf& buf);
-} // namespace Util
+
+[[nodiscard]] uint64_t readQWORDTag(Exiv2::BasicIo::UniquePtr& io) ;
+
+[[nodiscard]] uint32_t readDWORDTag(Exiv2::BasicIo::UniquePtr& io) ;
+
+[[nodiscard]] uint16_t readWORDTag(Exiv2::BasicIo::UniquePtr& io) ;
+
+[[nodiscard]] std::string readStringWcharTag(Exiv2::BasicIo::UniquePtr& io, uint16_t length) ;
+
+[[nodiscard]] std::string readStringTag(Exiv2::BasicIo::UniquePtr& io, uint16_t length=DWORD) ;
+
+} // namespace Exiv2
#endif // HELPER_FUNCTIONS_HPP
diff --git a/src/riffvideo.cpp b/src/riffvideo.cpp
index 15de358b..1f7b3bab 100644
--- a/src/riffvideo.cpp
+++ b/src/riffvideo.cpp
@@ -1,156 +1,105 @@
// ***************************************************************** -*- C++ -*-
-/*
- * Copyright (C) 2004-2021 Exiv2 authors
- * 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
- * asize_t with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
+/* Spec:
+ * https://learn.microsoft.com/fr-fr/windows/win32/directshow/avi-riff-file-reference
+ * https://cdn.hackaday.io/files/274271173436768/avi.pdf
+ * http://abcavi.kibi.ru/docs/odml1.pdf
*/
// *****************************************************************************
-// included header files
-#include "config.h"
-#include "basicio.hpp"
+// included header files
+#include "riffvideo.hpp"
#include "error.hpp"
#include "futils.hpp"
-#include "image_int.hpp"
-#include "riffvideo.hpp"
-#include "tags.hpp"
-#include "tags_int.hpp"
-#include "tiffimage_int.hpp"
-#include "types.hpp"
-// + standard includes
-#include
+#include "helper_functions.hpp"
-// *****************************************************************************
-// class member definitions
namespace Exiv2::Internal {
-/*!
- @brief Dummy TIFF header structure.
- */
-class DummyTiffHeader : public TiffHeaderBase {
- public:
- //! @name Creators
- //@{
- //! Default constructor
- DummyTiffHeader(ByteOrder byteOrder);
- //! Destructor
- ~DummyTiffHeader() override = default;
- //@}
-
- //! @name Manipulators
- //@{
- //! Dummy read function. Does nothing and returns true.
- bool read(const byte* pData, size_t size) override;
- //@}
-
-}; // class TiffHeader
-
-DummyTiffHeader::DummyTiffHeader(ByteOrder byteOrder) : TiffHeaderBase(42, 0, byteOrder, 0) {
-}
-
-bool DummyTiffHeader::read(const byte* /*pData*/, size_t /*size*/) {
- return true;
-}
-
-constexpr TagVocabulary infoTags[] = {{"AGES", "Xmp.video.Rated"},
- {"CMNT", "Xmp.video.Comment"},
- {"CODE", "Xmp.video.EncodedBy"},
- {"COMM", "Xmp.video.Comment"},
- {"DIRC", "Xmp.video.Director"},
- {"DISP", "Xmp.audio.SchemeTitle"},
- {"DTIM", "Xmp.video.DateTimeOriginal"},
- {"GENR", "Xmp.video.Genre"},
- {"IARL", "Xmp.video.ArchivalLocation"},
- {"IART", "Xmp.video.Artist"},
- {"IAS1", "Xmp.video.Edit1"},
- {"IAS2", "Xmp.video.Edit2"},
- {"IAS3", "Xmp.video.Edit3"},
- {"IAS4", "Xmp.video.Edit4"},
- {"IAS5", "Xmp.video.Edit5"},
- {"IAS6", "Xmp.video.Edit6"},
- {"IAS7", "Xmp.video.Edit7"},
- {"IAS8", "Xmp.video.Edit8"},
- {"IAS9", "Xmp.video.Edit9"},
- {"IBSU", "Xmp.video.BaseURL"},
- {"ICAS", "Xmp.audio.DefaultStream"},
- {"ICDS", "Xmp.video.CostumeDesigner"},
- {"ICMS", "Xmp.video.Commissioned"},
- {"ICMT", "Xmp.video.Comment"},
- {"ICNM", "Xmp.video.Cinematographer"},
- {"ICNT", "Xmp.video.Country"},
- {"ICOP", "Xmp.video.Copyright"},
- {"ICRD", "Xmp.video.DateTimeDigitized"},
- {"ICRP", "Xmp.video.Cropped"},
- {"IDIM", "Xmp.video.Dimensions"},
- {"IDPI", "Xmp.video.DotsPerInch"},
- {"IDST", "Xmp.video.DistributedBy"},
- {"IEDT", "Xmp.video.EditedBy"},
- {"IENC", "Xmp.video.EncodedBy"},
- {"IENG", "Xmp.video.Engineer"},
- {"IGNR", "Xmp.video.Genre"},
- {"IKEY", "Xmp.video.PerformerKeywords"},
- {"ILGT", "Xmp.video.Lightness"},
- {"ILGU", "Xmp.video.LogoURL"},
- {"ILIU", "Xmp.video.LogoIconURL"},
- {"ILNG", "Xmp.video.Language"},
- {"IMBI", "Xmp.video.InfoBannerImage"},
- {"IMBU", "Xmp.video.InfoBannerURL"},
- {"IMED", "Xmp.video.Medium"},
- {"IMIT", "Xmp.video.InfoText"},
- {"IMIU", "Xmp.video.InfoURL"},
- {"IMUS", "Xmp.video.MusicBy"},
- {"INAM", "Xmp.video.Title"},
- {"IPDS", "Xmp.video.ProductionDesigner"},
- {"IPLT", "Xmp.video.NumOfColors"},
- {"IPRD", "Xmp.video.Product"},
- {"IPRO", "Xmp.video.ProducedBy"},
- {"IRIP", "Xmp.video.RippedBy"},
- {"IRTD", "Xmp.video.Rating"},
- {"ISBJ", "Xmp.video.Subject"},
- {"ISFT", "Xmp.video.Software"},
- {"ISGN", "Xmp.video.SecondaryGenre"},
- {"ISHP", "Xmp.video.Sharpness"},
- {"ISRC", "Xmp.video.Source"},
- {"ISRF", "Xmp.video.SourceForm"},
- {"ISTD", "Xmp.video.ProductionStudio"},
- {"ISTR", "Xmp.video.Starring"},
- {"ITCH", "Xmp.video.Technician"},
- {"IWMU", "Xmp.video.WatermarkURL"},
- {"IWRI", "Xmp.video.WrittenBy"},
- {"LANG", "Xmp.video.Language"},
- {"LOCA", "Xmp.video.LocationInfo"},
- {"PRT1", "Xmp.video.Part"},
- {"PRT2", "Xmp.video.NumOfParts"},
- {"RATE", "Xmp.video.Rate"},
- {"STAR", "Xmp.video.Starring"},
- {"STAT", "Xmp.video.Statistics"},
- {"TAPE", "Xmp.video.TapeName"},
- {"TCDO", "Xmp.video.EndTimecode"},
- {"TCOD", "Xmp.video.StartTimecode"},
- {"TITL", "Xmp.video.Title"},
- {"TLEN", "Xmp.video.Length"},
- {"TORG", "Xmp.video.Organization"},
- {"TRCK", "Xmp.video.TrackNumber"},
- {"TURL", "Xmp.video.URL"},
- {"TVER", "Xmp.video.SoftwareVersion"},
- {"VMAJ", "Xmp.video.VegasVersionMajor"},
- {"VMIN", "Xmp.video.VegasVersionMinor"},
- {"YEAR", "Xmp.video.Year"}};
-
-constexpr TagDetails audioEncodingValues[] = {
+const std::map infoTags = {{"AGES", "Xmp.video.Rated"},
+ {"CMNT", "Xmp.video.Comment"},
+ {"CODE", "Xmp.video.EncodedBy"},
+ {"COMM", "Xmp.video.Comment"},
+ {"DIRC", "Xmp.video.Director"},
+ {"DISP", "Xmp.audio.SchemeTitle"},
+ {"DTIM", "Xmp.video.DateTimeOriginal"},
+ {"GENR", "Xmp.video.Genre"},
+ {"IARL", "Xmp.video.ArchivalLocation"},
+ {"IART", "Xmp.video.Artist"},
+ {"IAS1", "Xmp.video.Edit1"},
+ {"IAS2", "Xmp.video.Edit2"},
+ {"IAS3", "Xmp.video.Edit3"},
+ {"IAS4", "Xmp.video.Edit4"},
+ {"IAS5", "Xmp.video.Edit5"},
+ {"IAS6", "Xmp.video.Edit6"},
+ {"IAS7", "Xmp.video.Edit7"},
+ {"IAS8", "Xmp.video.Edit8"},
+ {"IAS9", "Xmp.video.Edit9"},
+ {"IBSU", "Xmp.video.BaseURL"},
+ {"ICAS", "Xmp.audio.DefaultStream"},
+ {"ICDS", "Xmp.video.CostumeDesigner"},
+ {"ICMS", "Xmp.video.Commissioned"},
+ {"ICMT", "Xmp.video.Comment"},
+ {"ICNM", "Xmp.video.Cinematographer"},
+ {"ICNT", "Xmp.video.Country"},
+ {"ICOP", "Xmp.video.Copyright"},
+ {"ICRD", "Xmp.video.DateTimeDigitized"},
+ {"ICRP", "Xmp.video.Cropped"},
+ {"IDIM", "Xmp.video.Dimensions"},
+ {"IDPI", "Xmp.video.DotsPerInch"},
+ {"IDST", "Xmp.video.DistributedBy"},
+ {"IEDT", "Xmp.video.EditedBy"},
+ {"IENC", "Xmp.video.EncodedBy"},
+ {"IENG", "Xmp.video.Engineer"},
+ {"IGNR", "Xmp.video.Genre"},
+ {"IKEY", "Xmp.video.PerformerKeywords"},
+ {"ILGT", "Xmp.video.Lightness"},
+ {"ILGU", "Xmp.video.LogoURL"},
+ {"ILIU", "Xmp.video.LogoIconURL"},
+ {"ILNG", "Xmp.video.Language"},
+ {"IMBI", "Xmp.video.InfoBannerImage"},
+ {"IMBU", "Xmp.video.InfoBannerURL"},
+ {"IMED", "Xmp.video.Medium"},
+ {"IMIT", "Xmp.video.InfoText"},
+ {"IMIU", "Xmp.video.InfoURL"},
+ {"IMUS", "Xmp.video.MusicBy"},
+ {"INAM", "Xmp.video.Title"},
+ {"IPDS", "Xmp.video.ProductionDesigner"},
+ {"IPLT", "Xmp.video.NumOfColors"},
+ {"IPRD", "Xmp.video.Product"},
+ {"IPRO", "Xmp.video.ProducedBy"},
+ {"IRIP", "Xmp.video.RippedBy"},
+ {"IRTD", "Xmp.video.Rating"},
+ {"ISBJ", "Xmp.video.Subject"},
+ {"ISFT", "Xmp.video.Software"},
+ {"ISGN", "Xmp.video.SecondaryGenre"},
+ {"ISHP", "Xmp.video.Sharpness"},
+ {"ISRC", "Xmp.video.Source"},
+ {"ISRF", "Xmp.video.SourceForm"},
+ {"ISTD", "Xmp.video.ProductionStudio"},
+ {"ISTR", "Xmp.video.Starring"},
+ {"ITCH", "Xmp.video.Technician"},
+ {"IWMU", "Xmp.video.WatermarkURL"},
+ {"IWRI", "Xmp.video.WrittenBy"},
+ {"LANG", "Xmp.video.Language"},
+ {"LOCA", "Xmp.video.LocationInfo"},
+ {"PRT1", "Xmp.video.Part"},
+ {"PRT2", "Xmp.video.NumOfParts"},
+ {"RATE", "Xmp.video.Rate"},
+ {"STAR", "Xmp.video.Starring"},
+ {"STAT", "Xmp.video.Statistics"},
+ {"TAPE", "Xmp.video.TapeName"},
+ {"TCDO", "Xmp.video.EndTimecode"},
+ {"TCOD", "Xmp.video.StartTimecode"},
+ {"TITL", "Xmp.video.Title"},
+ {"TLEN", "Xmp.video.Length"},
+ {"TORG", "Xmp.video.Organization"},
+ {"TRCK", "Xmp.video.TrackNumber"},
+ {"TURL", "Xmp.video.URL"},
+ {"TVER", "Xmp.video.SoftwareVersion"},
+ {"VMAJ", "Xmp.video.VegasVersionMajor"},
+ {"VMIN", "Xmp.video.VegasVersionMinor"},
+ {"YEAR", "Xmp.video.Year"}};
+
+const std::map audioEncodingValues = {
{0x1, "Microsoft PCM"},
{0x2, "Microsoft ADPCM"},
{0x3, "Microsoft IEEE float"},
@@ -395,36 +344,13 @@ constexpr TagDetails audioEncodingValues[] = {
{0xfffe, "Extensible"},
{0xffff, "Development"}};
-constexpr TagDetails nikonAVITags[] = {{0x0003, "Xmp.video.Make"},
- {0x0004, "Xmp.video.Model"},
- {0x0005, "Xmp.video.Software"},
- {0x0006, "Xmp.video.Equipment"},
- {0x0007, "Xmp.video.Orientation"},
- {0x0008, "Xmp.video.ExposureTime"},
- {0x0009, "Xmp.video.FNumber"},
- {0x000a, "Xmp.video.ExposureCompensation"},
- {0x000b, "Xmp.video.MaxApertureValue"},
- {0x000c, "Xmp.video.MeteringMode"},
- {0x000f, "Xmp.video.FocalLength"},
- {0x0010, "Xmp.video.XResolution"},
- {0x0011, "Xmp.video.YResolution"},
- {0x0012, "Xmp.video.ResolutionUnit"},
- {0x0013, "Xmp.video.DateTimeOriginal"},
- {0x0014, "Xmp.video.DateTimeDigitized"},
- {0x0016, "Xmp.video.duration"},
- {0x0018, "Xmp.video.FocusMode"},
- {0x001b, "Xmp.video.DigitalZoomRatio"},
- {0x001d, "Xmp.video.ColorMode"},
- {0x001e, "Xmp.video.Sharpness"},
- {0x001f, "Xmp.video.WhiteBalance"},
- {0x0020, "Xmp.video.ColorNoiseReduction"}};
-
-enum streamTypeInfo { Audio = 1, MIDI, Text, Video };
-
} // namespace Exiv2::Internal
+// *****************************************************************************
+// class member definitions
namespace Exiv2 {
-using namespace Exiv2::Internal;
+
+enum streamTypeInfo { Audio = 1, MIDI, Text, Video };
RiffVideo::RiffVideo(BasicIo::UniquePtr io) : Image(ImageType::riff, mdNone, std::move(io)) {
} // RiffVideo::RiffVideo
@@ -433,82 +359,10 @@ std::string RiffVideo::mimeType() const {
return "video/riff";
}
-/*!
- @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 RiffVideo::equalsRiffTag(Exiv2::DataBuf& buf, const char* str) {
- for (size_t i = 0; i < RIFF_TAG_SIZE; i++)
- if (toupper(buf.data()[i]) != str[i])
- return false;
- return true;
-}
-
void RiffVideo::printStructure(std::ostream& out, PrintStructureOption option, size_t depth) {
if (io_->open() != 0) {
throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
}
- // Ensure this is the correct image type
- if (!isRiffType(*io_, true)) {
- if (io_->error() || io_->eof())
- throw Error(ErrorCode::kerFailedToReadImageData);
- throw Error(ErrorCode::kerNotAnImage, "RIFF");
- }
-
- bool bPrint = option == kpsBasic || option == kpsRecursive;
- if (bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase) {
- byte data[RIFF_TAG_SIZE * 2];
- io_->read(data, RIFF_TAG_SIZE * 2);
- uint64_t filesize = Exiv2::getULong(data + RIFF_TAG_SIZE, littleEndian);
- DataBuf chunkId(5);
-
- if (bPrint) {
- out << Internal::indent(depth) << "STRUCTURE OF RIFF FILE: " << io().path() << std::endl;
- out << Internal::indent(depth) << Internal::stringFormat(" Chunk | Length | Offset | Payload")
- << std::endl;
- }
-
- const uint64_t bufMaxSize = 200;
- io_->seek(0, BasicIo::beg); // rewind
- while (!io_->eof() && static_cast(io_->tell()) < filesize) {
- auto offset = static_cast(io_->tell());
- byte size_buff[RIFF_TAG_SIZE];
- io_->read(chunkId.data(), RIFF_TAG_SIZE);
- io_->read(size_buff, RIFF_TAG_SIZE);
- uint32_t size = Exiv2::getULong(size_buff, littleEndian);
- if (size > bufMaxSize) {
- io_->seek(size, BasicIo::cur);
- continue;
- }
- DataBuf payload(offset ? size : RIFF_TAG_SIZE); // header is different from chunks
- io_->read(payload.data(), payload.size());
-
- if (bPrint) {
- out << Internal::indent(depth)
- << Internal::stringFormat(" %s | %12u | %12u | ", reinterpret_cast(chunkId.data()), size,
- static_cast(offset))
- << Internal::binaryToString(makeSlice(payload, 0, payload.size() > 32 ? 32 : payload.size())) << std::endl;
- }
-
- if (equalsRiffTag(chunkId, RIFF_CHUNK_HEADER_EXIF) && option == kpsRecursive) {
- // create MemIo object with the payload, then print the structure
- MemIo p(payload.c_data(), payload.size());
- printTiffStructure(p, out, option, depth);
- }
-
- bool bPrintPayload = (equalsRiffTag(chunkId, RIFF_CHUNK_HEADER_XMP) && option == kpsXMP) ||
- (equalsRiffTag(chunkId, RIFF_CHUNK_HEADER_ICCP) && option == kpsIccProfile);
- if (bPrintPayload) {
- out.write(reinterpret_cast(payload.data()), payload.size());
- }
-
- if (offset && io_->tell() % 2)
- io_->seek(+1, BasicIo::cur); // skip padding byte on sub-chunks
- }
- }
} // RiffVideo::printStructure
void RiffVideo::writeMetadata() {
@@ -527,658 +381,386 @@ void RiffVideo::readMetadata() {
IoCloser closer(*io_);
clearMetadata();
- continueTraversing_ = true;
- xmpData_["Xmp.video.FileSize"] = io_->size() / 1048576.;
+ xmpData_["Xmp.video.FileSize"] = io_->size();
xmpData_["Xmp.video.MimeType"] = mimeType();
- DataBuf buf(RIFF_TAG_SIZE + 1);
+ HeaderReader header(io_);
+ xmpData_["Xmp.video.Container"] = header.getId();
- io_->read(buf.data(), RIFF_TAG_SIZE);
- xmpData_["Xmp.video.Container"] = buf.data();
+ DataBuf FileType = io_->read(DWORD);
+ xmpData_["Xmp.video.FileType"] = FileType.data();
- io_->read(buf.data(), RIFF_TAG_SIZE);
- io_->read(buf.data(), RIFF_TAG_SIZE);
- xmpData_["Xmp.video.FileType"] = buf.data();
-
- while (continueTraversing_)
- decodeBlock();
+ decodeBlocks();
} // RiffVideo::readMetadata
-void RiffVideo::decodeBlock() {
- DataBuf chunk_size(RIFF_TAG_SIZE + 1);
- DataBuf chunk_id(RIFF_TAG_SIZE + 1);
-
- io_->read(chunk_id.data(), RIFF_TAG_SIZE);
+RiffVideo::HeaderReader::HeaderReader(BasicIo::UniquePtr& io) {
+ if (io->size() >= io->tell() + DWORD + DWORD) {
+ DataBuf IdBuf_ = io->read(DWORD);
+ id_ = Exiv2::toString(IdBuf_.data());
- if (io_->eof() || equalsRiffTag(chunk_id, RIFF_CHUNK_ID_MOVI) || equalsRiffTag(chunk_id, RIFF_CHUNK_ID_DATA)) {
- continueTraversing_ = false;
- return;
- }
- if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_HDRL) || equalsRiffTag(chunk_id, RIFF_CHUNK_ID_STRL)) {
- decodeBlock();
- } else {
- io_->read(chunk_size.data(), RIFF_TAG_SIZE);
- size_t size = Exiv2::getULong(chunk_size.data(), littleEndian);
-
- tagDecoder(chunk_id, size);
- }
-} // RiffVideo::decodeBlock
-
-void RiffVideo::tagDecoder(Exiv2::DataBuf& chunk_id, size_t size) {
- uint64_t cur_pos = io_->tell();
- static bool listFlag = false, listEnd = false;
-
- if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_LIST)) {
- listFlag = true;
- listEnd = false;
-
- while (static_cast(io_->tell()) < cur_pos + size && !io_->eof()) {
- decodeBlock();
- }
- listEnd = true;
- io_->seek(cur_pos + size, BasicIo::beg);
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_JUNK) && listEnd) {
- junkHandler(size);
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_AVIH)) {
- listFlag = false;
- aviHeaderTagsHandler(size);
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_STRH)) {
- listFlag = false;
- streamHandler(size);
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_STRF) || equalsRiffTag(chunk_id, RIFF_CHUNK_ID_FMT)) {
- listFlag = false;
- if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_FMT))
- streamType_ = Audio;
- streamFormatHandler(size);
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_STRN)) {
- listFlag = false;
- dateTimeOriginal(size, 1);
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_STRD)) {
- listFlag = false;
- streamDataTagHandler(size);
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_IDIT)) {
- listFlag = false;
- dateTimeOriginal(size);
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_INFO)) {
- listFlag = false;
- infoTagsHandler();
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_NCDT)) {
- listFlag = false;
- nikonTagsHandler();
- } else if (equalsRiffTag(chunk_id, RIFF_CHUNK_ID_ODML)) {
- listFlag = false;
- odmlTagsHandler();
- } else if (listFlag) {
- skipListData();
- } else {
- io_->seek(cur_pos + size, BasicIo::beg);
+ size_ = readDWORDTag(io);
}
-} // RiffVideo::tagDecoder
+}
-void RiffVideo::streamDataTagHandler(size_t size) {
- const size_t bufMinSize = 20000;
- DataBuf buf(bufMinSize);
- uint64_t cur_pos = io_->tell();
+bool RiffVideo::equal(const std::string& str1, const std::string& str2) {
+ if (str1.size() != str2.size())
+ return false;
+ for (size_t i = 0; i < str1.size(); i++)
+ if (toupper(str1[i]) != str2[i])
+ return false;
+ return true;
+}
- io_->read(buf.data(), 8);
+void RiffVideo::readList(HeaderReader& header_) {
+ DataBuf FormTypeBuf_ = io_->read(DWORD);
- if (equalsRiffTag(buf, "AVIF")) {
- if (size < RIFF_TAG_SIZE) {
-#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.data(), size - RIFF_TAG_SIZE);
-
- IptcData iptcData;
- XmpData xmpData;
- DummyTiffHeader tiffHeader(littleEndian);
- TiffParserWorker::decode(exifData_, iptcData, xmpData, buf.data(), 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";
- }
+#ifdef EXIV2_DEBUG_MESSAGES
+ EXV_DEBUG << "-> Reading list : id= " << header_.getId() << " type= " << Exiv2::toString(FormTypeBuf_.data())
+ << " size= " << header_.getSize() << "(" << io_->tell() << "/" << io_->size() << ")" << std::endl;
#endif
- }
- }
- // TODO decode CasioData and ZORA Tag
- io_->seek(cur_pos + size, BasicIo::beg);
-
-} // RiffVideo::streamDataTagHandler
-
-void RiffVideo::dateTimeOriginal(size_t size, int i) {
- uint64_t cur_pos = io_->tell();
- const size_t bufMinSize = 100;
- DataBuf buf(bufMinSize);
- io_->read(buf.data(), size);
- if (!i)
- xmpData_["Xmp.video.DateUTC"] = buf.data();
- else
- xmpData_["Xmp.video.StreamName"] = buf.data();
- io_->seek(cur_pos + size, BasicIo::beg);
-} // RiffVideo::dateTimeOriginal
-
-void RiffVideo::odmlTagsHandler() {
- const size_t bufMinSize = 100;
- DataBuf buf(bufMinSize);
- io_->seek(-12, BasicIo::cur);
- io_->read(buf.data(), RIFF_TAG_SIZE);
- size_t size = Exiv2::getULong(buf.data(), littleEndian);
- size_t size2 = size;
-
- uint64_t cur_pos = io_->tell();
- io_->read(buf.data(), RIFF_TAG_SIZE);
- size -= RIFF_TAG_SIZE;
-
- while (size > 0) {
- io_->read(buf.data(), RIFF_TAG_SIZE);
- size -= RIFF_TAG_SIZE;
- if (equalsRiffTag(buf, "DMLH")) {
- io_->read(buf.data(), RIFF_TAG_SIZE);
- size -= RIFF_TAG_SIZE;
- io_->read(buf.data(), RIFF_TAG_SIZE);
- size -= RIFF_TAG_SIZE;
- xmpData_["Xmp.video.TotalFrameCount"] = Exiv2::getULong(buf.data(), littleEndian);
- }
+
+ if (equal(Exiv2::toString(FormTypeBuf_.data()), CHUNK_ID_INFO))
+ readInfoListChunk(header_.getSize());
+ else if (equal(Exiv2::toString(FormTypeBuf_.data()), CHUNK_ID_MOVI)) {
+ readMoviList(header_.getSize());
}
- io_->seek(cur_pos + size2, BasicIo::beg);
-} // RiffVideo::odmlTagsHandler
-
-void RiffVideo::skipListData() {
- DataBuf buf(RIFF_TAG_SIZE + 1);
- io_->seek(-12, BasicIo::cur);
- io_->read(buf.data(), RIFF_TAG_SIZE);
- size_t size = Exiv2::getULong(buf.data(), littleEndian);
-
- uint64_t cur_pos = io_->tell();
- io_->seek(cur_pos + size, BasicIo::beg);
-} // RiffVideo::skipListData
-
-void RiffVideo::copyTagValue(DataBuf& buf_dest, DataBuf& buf_src, size_t index) {
- buf_dest.data()[0] = buf_src.data()[0 + index];
- buf_dest.data()[1] = buf_src.data()[1 + index];
- buf_dest.data()[2] = buf_src.data()[2 + index];
- buf_dest.data()[3] = buf_src.data()[3 + index];
}
-void RiffVideo::nikonTagsHandler() {
- const size_t bufMinSize = 100;
- DataBuf buf(bufMinSize), buf2(RIFF_TAG_SIZE + 1);
- io_->seek(-12, BasicIo::cur);
- io_->read(buf.data(), RIFF_TAG_SIZE);
-
- size_t internal_size = 0, tagID = 0, dataSize = 0, tempSize, size = Exiv2::getULong(buf.data(), 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.data(), RIFF_TAG_SIZE);
- tempSize -= RIFF_TAG_SIZE;
-
- while (tempSize > 0) {
- std::memset(buf.data(), 0x0, buf.size());
- io_->read(buf.data(), RIFF_TAG_SIZE);
- io_->read(buf2.data(), RIFF_TAG_SIZE);
- size_t temp = internal_size = Exiv2::getULong(buf2.data(), littleEndian);
- internal_pos = io_->tell();
- tempSize -= (internal_size + 8);
-
- if (equalsRiffTag(buf, "NCVR")) {
- while (temp > 3) {
- std::memset(buf.data(), 0x0, buf.size());
- io_->read(buf.data(), 2);
- tagID = Exiv2::getULong(buf.data(), littleEndian);
- io_->read(buf.data(), 2);
- dataSize = Exiv2::getULong(buf.data(), littleEndian);
- temp -= (RIFF_TAG_SIZE + 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";
+void RiffVideo::readChunk(HeaderReader& header_) {
+#ifdef EXIV2_DEBUG_MESSAGES
+ EXV_DEBUG << "--> Reading Chunk : [" << header_.getId() << "] size= " << header_.getSize() << "(" << io_->tell()
+ << "/" << io_->size() << ")" << std::endl;
#endif
- } else {
- io_->read(buf.data(), dataSize);
- xmpData_["Xmp.video.MakerNoteType"] = buf.data();
- }
- } else if (tagID == 0x0002) {
- while (dataSize) {
- std::memset(buf.data(), 0x0, buf.size());
- io_->read(buf.data(), 1);
- str[(RIFF_TAG_SIZE - dataSize) * 2] = static_cast(Exiv2::getULong(buf.data(), littleEndian) + 48);
- --dataSize;
- }
- xmpData_["Xmp.video.MakerNoteVersion"] = str;
- }
- }
- } else if (equalsRiffTag(buf, "NCTG")) {
- while (temp > 3) {
- std::memset(buf.data(), 0x0, buf.size());
- io_->read(buf.data(), 2);
- tagID = Exiv2::getULong(buf.data(), littleEndian);
- io_->read(buf.data(), 2);
- dataSize = Exiv2::getULong(buf.data(), littleEndian);
- temp -= (RIFF_TAG_SIZE + 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
- } else {
- io_->read(buf.data(), dataSize);
-
- 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.data();
- break;
-
- case 0x0007:
- case 0x0010:
- case 0x0011:
- case 0x000c:
- case 0x0012:
- xmpData_[exvGettext(td->label_)] = Exiv2::getULong(buf.data(), littleEndian);
- break;
-
- case 0x0008:
- case 0x0009:
- case 0x000a:
- case 0x000b:
- case 0x000f:
- case 0x001b:
- case 0x0016:
- copyTagValue(buf2, buf);
- denominator = static_cast(Exiv2::getLong(buf2.data(), littleEndian));
- if (denominator != 0)
- xmpData_[exvGettext(td->label_)] = Exiv2::getLong(buf.data(), littleEndian) / denominator;
- else
- xmpData_[exvGettext(td->label_)] = 0;
- break;
-
- default:
- break;
- }
- }
- }
- }
-
- else if (equalsRiffTag(buf, "NCTH")) { // TODO Nikon Thumbnail Image
- }
- else if (equalsRiffTag(buf, "NCVW")) { // TODO Nikon Preview Image
- }
-
- io_->seek(internal_pos + internal_size, BasicIo::beg);
+ if (equal(header_.getId(), CHUNK_ID_AVIH))
+ readAviHeader();
+ else if (equal(header_.getId(), CHUNK_ID_STRH))
+ readStreamHeader();
+ else if (equal(header_.getId(), CHUNK_ID_STRF))
+ readStreamFormat(header_.getSize());
+ else if (equal(header_.getId(), CHUNK_ID_FMT)) {
+ streamType_ = Audio;
+ readStreamFormat(header_.getSize());
+ } else if (equal(header_.getId(), CHUNK_ID_STRD))
+ readStreamData(header_.getSize());
+ else if (equal(header_.getId(), CHUNK_ID_STRN))
+ StreamName(header_.getSize());
+ else if (equal(header_.getId(), CHUNK_ID_VPRP))
+ readVPRPChunk(header_.getSize());
+ else if (equal(header_.getId(), CHUNK_ID_IDX1))
+ readIndexChunk(header_.getSize());
+ else if (equal(header_.getId(), CHUNK_ID_DATA))
+ readDataChunk(header_.getSize());
+ else if (equal(header_.getId(), CHUNK_ID_JUNK))
+ readJunk(header_.getSize());
+ else {
+#ifdef EXIV2_DEBUG_MESSAGES
+ EXV_DEBUG << "--> Ignoring Chunk : " << header_.getId() << "] size= " << header_.getSize() << "(" << io_->tell()
+ << "/" << io_->size() << ")" << std::endl;
+#endif
+ io_->seekOrThrow(io_->tell() + header_.getSize(), BasicIo::beg, ErrorCode::kerFailedToReadImageData);
}
+}
- if (size == 0) {
- io_->seek(cur_pos + RIFF_TAG_SIZE, BasicIo::beg);
+void RiffVideo::decodeBlocks() {
+ HeaderReader header(io_);
+ if (equal(header.getId(), CHUNK_ID_LIST)) {
+ readList(header);
} else {
- io_->seek(cur_pos + size, BasicIo::beg);
+ readChunk(header);
}
-} // RiffVideo::nikonTagsHandler
-
-void RiffVideo::infoTagsHandler() {
- const size_t bufMinSize = 10000;
- DataBuf buf(bufMinSize);
- io_->seek(-12, BasicIo::cur);
- io_->read(buf.data(), RIFF_TAG_SIZE);
- uint32_t infoSize, size = Exiv2::getULong(buf.data(), littleEndian);
- uint32_t size_external = size;
- const TagVocabulary* tv;
-
- uint64_t cur_pos = io_->tell();
- io_->read(buf.data(), RIFF_TAG_SIZE);
- size -= RIFF_TAG_SIZE;
-
- while (size >= RIFF_TAG_SIZE) {
- io_->read(buf.data(), RIFF_TAG_SIZE);
- size -= RIFF_TAG_SIZE;
- if (!Exiv2::getULong(buf.data(), littleEndian))
- break;
- tv = find(infoTags, Exiv2::toString(buf.data()));
- io_->read(buf.data(), RIFF_TAG_SIZE);
- size -= RIFF_TAG_SIZE;
- infoSize = Exiv2::getULong(buf.data(), littleEndian);
-
- size -= infoSize;
- io_->read(buf.data(), infoSize);
- if (infoSize < RIFF_TAG_SIZE)
- buf.data()[infoSize] = '\0';
-
- if (tv)
- xmpData_[exvGettext(tv->label_)] = buf.data();
- else
- continue;
+
+ if (!io_->eof() && io_->tell() < io_->size()) {
+ decodeBlocks();
}
- io_->seek(cur_pos + size_external, BasicIo::beg);
-} // RiffVideo::infoTagsHandler
-void RiffVideo::junkHandler(size_t size) {
- DataBuf buf(size), buf2(RIFF_TAG_SIZE);
- uint64_t cur_pos = io_->tell();
+} // RiffVideo::decodeBlock
- io_->read(buf.data(), RIFF_TAG_SIZE);
- //! Pentax Metadata and Tags
- if (equalsRiffTag(buf, "PENT")) {
- io_->seek(cur_pos + 18, BasicIo::beg);
- io_->read(buf.data(), 26);
- xmpData_["Xmp.video.Make"] = buf.data();
+void RiffVideo::readAviHeader() {
+#ifdef EXIV2_DEBUG_MESSAGES
+ EXV_DEBUG << "--> dwMicroSecPerFrame = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwMaxBytesPerSec = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwPaddingGranularity = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwFlags = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwTotalFrames = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwInitialFrames = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwStreams = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwSuggestedBufferSize = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwWidth = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwHeight = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwReserved1 = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwReserved2 = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwReserved3 = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwReserved4 = " << readDWORDTag(io_) << std::endl;
+#else
- io_->read(buf.data(), 50);
- xmpData_["Xmp.video.Model"] = buf.data();
+ uint32_t TimeBetweenFrames = readDWORDTag(io_);
+ xmpData_["Xmp.video.MicroSecPerFrame"] = TimeBetweenFrames;
+ double frame_rate = 1000000. / TimeBetweenFrames;
- std::memset(buf.data(), 0x0, buf.size());
- io_->read(buf.data(), 8);
- copyTagValue(buf2, buf);
- xmpData_["Xmp.video.FNumber"] =
- static_cast(Exiv2::getLong(buf.data(), littleEndian)) / Exiv2::getLong(buf2.data(), littleEndian);
- ;
+ xmpData_["Xmp.video.MaxDataRate"] = readDWORDTag(io_); // MaximumDataRate
- io_->seek(cur_pos + 131, BasicIo::beg);
- io_->read(buf.data(), 26);
- xmpData_["Xmp.video.DateTimeOriginal"] = buf.data();
+ io_->seekOrThrow(io_->tell() + DWORD * 2, BasicIo::beg,
+ ErrorCode::kerFailedToReadImageData); // ignore PaddingGranularity and Flags
- io_->read(buf.data(), 26);
- xmpData_["Xmp.video.DateTimeDigitized"] = buf.data();
+ uint32_t frame_count = readDWORDTag(io_); // TotalNumberOfFrames
+ xmpData_["Xmp.video.FrameCount"] = frame_count;
- io_->seek(cur_pos + 299, BasicIo::beg);
- std::memset(buf.data(), 0x0, buf.size());
+ io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg,
+ ErrorCode::kerFailedToReadImageData); // ignore NumberOfInitialFrames
- io_->read(buf.data(), 2);
- Exiv2::XmpTextValue tv(Exiv2::toString(Exiv2::getLong(buf.data(), littleEndian)));
- xmpData_.add(Exiv2::XmpKey("Xmp.xmp.Thumbnails/xmpGImg:width"), &tv);
+ xmpData_["Xmp.audio.ChannelType"] = getStreamType(readDWORDTag(io_)); // NumberOfStreams
- io_->read(buf.data(), 2);
- tv.read(Exiv2::toString(Exiv2::getLong(buf.data(), littleEndian)));
- xmpData_.add(Exiv2::XmpKey("Xmp.xmp.Thumbnails/xmpGImg:height"), &tv);
+ xmpData_["Xmp.video.StreamCount"] = readDWORDTag(io_); // SuggestedBufferSize
- io_->read(buf.data(), RIFF_TAG_SIZE);
+ uint32_t width = readDWORDTag(io_);
+ xmpData_["Xmp.video.Width"] = width;
- // TODO - Storing the image Thumbnail in Base64 Format
+ uint32_t height = readDWORDTag(io_);
+ xmpData_["Xmp.video.Height"] = height;
- } else {
- io_->seek(cur_pos, BasicIo::beg);
- io_->read(buf.data(), size);
- xmpData_["Xmp.video.Junk"] = buf.data();
+ io_->seekOrThrow(io_->tell() + DWORD * 4, BasicIo::beg,
+ ErrorCode::kerFailedToReadImageData); // TimeScale, DataRate, StartTime, DataLength
+
+ fillAspectRatio(width, height);
+ fillDuration(frame_rate, frame_count);
+#endif
+}
+
+void RiffVideo::readStreamHeader() {
+ std::string stream = readStringTag(io_);
+ streamType_ = (equal(stream, "VIDS")) ? Video : Audio;
+
+#ifdef EXIV2_DEBUG_MESSAGES
+ EXV_DEBUG << "--> fccType = " << stream << std::endl;
+ EXV_DEBUG << "--> fccHandler = " << readStringTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwFlags = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> wPriority = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> wLanguage = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwInitialFrames = " << readDWORDTag(io_) << std::endl; // 20
+ EXV_DEBUG << "--> dwScale = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwRate = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwStart = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwLength = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> dwSuggestedBufferSize = " << readDWORDTag(io_) << std::endl; // 40
+ EXV_DEBUG << "--> dwSampleSize = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> Left = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> top = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> right = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> bottom = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> XXXXXX = " << readDWORDTag(io_) << std::endl; // 56
+
+#else
+
+ xmpData_["Xmp.video.Codec"] = readStringTag(io_); // DataHandler
+
+ io_->seekOrThrow(io_->tell() + DWORD * 2 + WORD * 2, BasicIo::beg,
+ ErrorCode::kerFailedToReadImageData); // dwFlags, wPriority, wLanguage, dwInitialFrames
+
+ uint32_t divisor = readDWORDTag(io_); // TimeScale
+
+ if (divisor) {
+ double rate = static_cast(readDWORDTag(io_) / divisor);
+ xmpData_[(streamType_ == Video) ? "Xmp.video.FrameRate" : "Xmp.audio.SampleRate"] = rate;
}
+ io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData); // dwStart
- io_->seek(cur_pos + size, BasicIo::beg);
-} // RiffVideo::junkHandler
-
-void RiffVideo::aviHeaderTagsHandler(size_t size) {
- DataBuf buf(RIFF_TAG_SIZE + 1);
- size_t width = 0, height = 0, frame_count = 0;
- double frame_rate = 1;
-
- uint64_t cur_pos = io_->tell();
-
- enum aviHeaderTags { frameRate, maxDataRate, frameCount = 4, streamCount = 6, imageWidth_h = 8, imageHeight_h, last };
- for (aviHeaderTags tag = frameRate; tag != aviHeaderTags::last; tag = static_cast(tag + 1)) {
- std::memset(buf.data(), 0x0, buf.size());
- io_->read(buf.data(), RIFF_TAG_SIZE);
-
- switch (tag) {
- case frameRate:
- xmpData_["Xmp.video.MicroSecPerFrame"] = Exiv2::getULong(buf.data(), littleEndian);
- frame_rate = 1000000. / Exiv2::getULong(buf.data(), littleEndian);
- break;
- case (maxDataRate):
- xmpData_["Xmp.video.MaxDataRate"] = Exiv2::getULong(buf.data(), littleEndian) / 1024.;
- break;
- case frameCount:
- frame_count = Exiv2::getULong(buf.data(), littleEndian);
- xmpData_["Xmp.video.FrameCount"] = frame_count;
- break;
- case streamCount:
- xmpData_["Xmp.video.StreamCount"] = Exiv2::getULong(buf.data(), littleEndian);
- break;
- case imageWidth_h:
- width = Exiv2::getULong(buf.data(), littleEndian);
- xmpData_["Xmp.video.Width"] = width;
- break;
- case imageHeight_h:
- height = Exiv2::getULong(buf.data(), littleEndian);
- xmpData_["Xmp.video.Height"] = height;
- break;
- default:
- break;
- }
+ if (divisor) {
+ double frame_count = static_cast(readDWORDTag(io_) / divisor); // DataLength
+ xmpData_[(streamType_ == Video) ? "Xmp.video.FrameCount" : "Xmp.audio.FrameCount"] = frame_count;
}
- fillAspectRatio(width, height);
- fillDuration(frame_rate, frame_count);
+ io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData); // dwSuggestedBufferSize
- io_->seek(cur_pos + size, BasicIo::beg);
-} // RiffVideo::aviHeaderTagsHandler
+ xmpData_[(streamType_ == Video) ? "Xmp.video.VideoQuality" : "Xmp.video.StreamQuality"] = readDWORDTag(io_);
-void RiffVideo::streamHandler(size_t size) {
- DataBuf buf(RIFF_TAG_SIZE + 1);
- size_t divisor = 1;
- uint64_t cur_pos = io_->tell();
+ xmpData_[(streamType_ == Video) ? "Xmp.video.VideoSampleSize" : "Xmp.video.StreamSampleSize"] = readDWORDTag(io_);
+ io_->seekOrThrow(io_->tell() + DWORD * 2, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+#endif
+}
- io_->read(buf.data(), RIFF_TAG_SIZE);
- if (equalsRiffTag(buf, "VIDS"))
- streamType_ = Video;
- else if (equalsRiffTag(buf, "AUDS"))
- streamType_ = Audio;
+void RiffVideo::readStreamFormat(uint64_t size_) {
+ // The structure of the strf chunk depends on the media type. Video streams use the BITMAPINFOHEADER structure,
+ // whereas audio streams use the WAVEFORMATEX structure.
- enum streamHeaderTags {
- codec = 1,
- sampleRateDivisor = 5,
- sampleRate = 6,
- sampleCount = 8,
- quality = 10,
- sampleSize = 11,
- last
- };
- for (streamHeaderTags tag = codec; tag != streamHeaderTags::last; tag = static_cast(tag + 1)) {
- std::memset(buf.data(), 0x0, buf.size());
- io_->read(buf.data(), RIFF_TAG_SIZE); // the position is advanced by the number of bytes read, that's why we need
- // to iterate sequentially , not only on switch values.
-
- switch (tag) {
- case codec:
- if (streamType_ == Video)
- xmpData_["Xmp.video.Codec"] = buf.data();
- else if (streamType_ == Audio)
- xmpData_["Xmp.audio.Codec"] = buf.data();
- else
- xmpData_["Xmp.video.Codec"] = buf.data();
- break;
- case sampleRateDivisor:
- divisor = Exiv2::getULong(buf.data(), littleEndian);
- break;
- case sampleRate:
- 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);
- break;
- case sampleCount:
- if (streamType_ == Video)
- xmpData_["Xmp.video.FrameCount"] = Exiv2::getULong(buf.data(), littleEndian);
- else if (streamType_ == Audio)
- xmpData_["Xmp.audio.SampleCount"] = Exiv2::getULong(buf.data(), littleEndian);
- else
- xmpData_["Xmp.video.StreamSampleCount"] = Exiv2::getULong(buf.data(), littleEndian);
- break;
- case quality:
- if (streamType_ == Video)
- xmpData_["Xmp.video.VideoQuality"] = Exiv2::getULong(buf.data(), littleEndian);
- else if (streamType_ != Audio)
- xmpData_["Xmp.video.StreamQuality"] = Exiv2::getULong(buf.data(), littleEndian);
- break;
- case sampleSize:
- if (streamType_ == Video)
- xmpData_["Xmp.video.VideoSampleSize"] = Exiv2::getULong(buf.data(), littleEndian);
- else if (streamType_ != Audio)
- xmpData_["Xmp.video.StreamSampleSize"] = Exiv2::getULong(buf.data(), littleEndian);
- break;
- default:
- break;
- }
+#ifdef EXIV2_DEBUG_MESSAGES
+ if (streamType_ == Video) {
+ EXV_DEBUG << "--> wFormatTag = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> nChannels = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> nSamplesPerSec = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> nAvgBytesPerSec = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> nBlockAlign = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> wBitsPerSample = " << readWORDTag(io_) << std::endl;
+ } else {
+ EXV_DEBUG << "--> biSize = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biWidth = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biHeight = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biPlanes = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biBitCount = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biCompression = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biSizeImage = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biXPelsPerMeter = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biYPelsPerMeter = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biClrUsed = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> biClrImportant = " << readDWORDTag(io_) << std::endl;
}
- io_->seek(cur_pos + size, BasicIo::beg);
-} // RiffVideo::streamHandler
-void RiffVideo::streamFormatHandler(size_t size) {
- DataBuf buf(RIFF_TAG_SIZE + 1);
- uint64_t cur_pos = io_->tell();
+#else
if (streamType_ == Video) {
- io_->read(buf.data(), RIFF_TAG_SIZE);
-
- enum bmptags {
- imageWidth,
- imageHeight,
- planes,
- bitDepth,
- compression,
- imageLength,
- pixelsPerMeterX,
- pixelsPerMeterY,
- numColors,
- numImportantColors,
- last
- };
- for (bmptags tag = imageWidth; tag != bmptags::last; tag = static_cast(tag + 1)) {
- std::memset(buf.data(), 0x0, buf.size());
-
- switch (tag) {
- case imageWidth: // Will be used in case of debugging
- io_->read(buf.data(), RIFF_TAG_SIZE);
- break;
- case imageHeight: // Will be used in case of debugging
- io_->read(buf.data(), RIFF_TAG_SIZE);
- break;
- case planes:
- io_->read(buf.data(), 2);
- xmpData_["Xmp.video.Planes"] = Exiv2::getUShort(buf.data(), littleEndian);
- break;
- case bitDepth:
- io_->read(buf.data(), 2);
- xmpData_["Xmp.video.PixelDepth"] = Exiv2::getUShort(buf.data(), littleEndian);
- break;
- case compression:
- io_->read(buf.data(), RIFF_TAG_SIZE);
- xmpData_["Xmp.video.Compressor"] = buf.data();
- break;
- case imageLength:
- io_->read(buf.data(), RIFF_TAG_SIZE);
- xmpData_["Xmp.video.ImageLength"] = Exiv2::getULong(buf.data(), littleEndian);
- break;
- case pixelsPerMeterX:
- io_->read(buf.data(), RIFF_TAG_SIZE);
- xmpData_["Xmp.video.PixelPerMeterX"] = Exiv2::getULong(buf.data(), littleEndian);
- break;
- case pixelsPerMeterY:
- io_->read(buf.data(), RIFF_TAG_SIZE);
- xmpData_["Xmp.video.PixelPerMeterY"] = Exiv2::getULong(buf.data(), littleEndian);
- break;
- case numColors:
- io_->read(buf.data(), RIFF_TAG_SIZE);
- if (Exiv2::getULong(buf.data(), littleEndian) == 0) {
- xmpData_["Xmp.video.NumOfColours"] = "Unspecified";
- } else {
- xmpData_["Xmp.video.NumOfColours"] = Exiv2::getULong(buf.data(), littleEndian);
- }
- break;
- case numImportantColors:
- io_->read(buf.data(), RIFF_TAG_SIZE);
- if (Exiv2::getULong(buf.data(), littleEndian)) {
- xmpData_["Xmp.video.NumIfImpColours"] = Exiv2::getULong(buf.data(), littleEndian);
- } else {
- xmpData_["Xmp.video.NumOfImpColours"] = "All";
- }
- break;
- default:
- break;
- }
- }
+ io_->seekOrThrow(io_->tell() + DWORD * 3, BasicIo::beg,
+ ErrorCode::kerFailedToReadImageData); // ignore biSize, biWidth, biHeight
+ xmpData_["Xmp.video.Planes"] = readWORDTag(io_);
+ xmpData_["Xmp.video.PixelDepth"] = readWORDTag(io_);
+ xmpData_["Xmp.video.Compressor"] = readStringTag(io_);
+ xmpData_["Xmp.video.ImageLength"] = readDWORDTag(io_);
+ xmpData_["Xmp.video.PixelPerMeterX"] = readQWORDTag(io_);
+ xmpData_["Xmp.video.PixelPerMeterY"] = readQWORDTag(io_);
+ uint32_t NumOfColours = readDWORDTag(io_);
+ if (NumOfColours == 0)
+ xmpData_["Xmp.video.NumOfColours"] = "Unspecified";
+ else
+ xmpData_["Xmp.video.NumOfColours"] = NumOfColours;
+ uint32_t NumIfImpColours = readDWORDTag(io_);
+ if (NumIfImpColours == 0)
+ xmpData_["Xmp.video.NumIfImpColours"] = "All";
+ else
+ xmpData_["Xmp.video.NumIfImpColours"] = NumIfImpColours;
} else if (streamType_ == Audio) {
- int c = 0;
- const TagDetails* td;
- enum audioFormatTags { encoding, numberOfChannels, audioSampleRate, avgBytesPerSec = 4, bitsPerSample = 7, last };
- for (audioFormatTags tag = encoding; tag != audioFormatTags::last; tag = static_cast(tag + 1)) {
- io_->read(buf.data(), 2);
-
- switch (tag) {
- case encoding:
- td = find(audioEncodingValues, Exiv2::getUShort(buf.data(), littleEndian));
- if (td) {
- xmpData_["Xmp.audio.Compressor"] = exvGettext(td->label_);
- } else {
- xmpData_["Xmp.audio.Compressor"] = Exiv2::getUShort(buf.data(), littleEndian);
- }
- break;
- case numberOfChannels:
- c = Exiv2::getUShort(buf.data(), 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.data(), littleEndian);
- break;
- case avgBytesPerSec:
- xmpData_["Xmp.audio.SampleType"] = Exiv2::getUShort(buf.data(), littleEndian);
- break;
- case bitsPerSample:
- xmpData_["Xmp.audio.BitsPerSample"] = Exiv2::getUShort(buf.data(), littleEndian);
- io_->read(buf.data(), 2);
- break;
- default:
- break;
- }
+ uint16_t format_tag = readWORDTag(io_);
+ auto it = Internal::audioEncodingValues.find(format_tag);
+ if (it != Internal::audioEncodingValues.end()) {
+ xmpData_["Xmp.audio.Compressor"] = it->second;
+ } else {
+ xmpData_["Xmp.audio.Compressor"] = format_tag;
}
+
+ xmpData_["Xmp.audio.ChannelType"] = getStreamType(readDWORDTag(io_));
+ xmpData_["Xmp.audio.SampleRate"] = readDWORDTag(io_); // nSamplesPerSec
+ io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData); // nAvgBytesPerSec
+ xmpData_["Xmp.audio.SampleType"] = readDWORDTag(io_); // nBlockAlign
+ xmpData_["Xmp.audio.BitsPerSample"] = readDWORDTag(io_); // wBitsPerSample
+
+#endif
+ if (xmpData_["Xmp.video.FileType"].toString() == "AVI ")
+ io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData); // cbSize
+}
+else {
+ io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+}
+
+}
+
+void RiffVideo::readStreamData(uint64_t size_) {
+ io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+}
+
+void RiffVideo::StreamName(uint64_t size_) {
+ // This element contains a name for the stream. That stream name should only use plain ASCII, especially not UTF-8.
+ io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+}
+
+void RiffVideo::readInfoListChunk(uint64_t size_) {
+ uint64_t current_size = DWORD;
+ while (current_size < size_) {
+ std::string type = readStringTag(io_);
+ size_t size = readDWORDTag(io_);
+ std::string content = readStringTag(io_, size);
+ auto it = Internal::infoTags.find(type);
+ if (it != Internal::infoTags.end()) {
+ xmpData_[it->second] = content;
+ }
+ current_size += DWORD * 2 + size;
+ }
+}
+
+void RiffVideo::readMoviList(uint64_t size_) {
+ io_->seekOrThrow(io_->tell() + size_ - DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+}
+
+void RiffVideo::readVPRPChunk(uint64_t size_) {
+#ifdef EXIV2_DEBUG_MESSAGES
+ EXV_DEBUG << "--> VideoFormatToken = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> VideoStandard = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> VerticalRefreshRate = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> HTotalInT = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> VTotalInLines = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> FrameAspectRatio Height = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> FrameAspectRatio Width = " << readWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> FrameWidthInPixels = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> FrameHeightInLines = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> CompressedBMHeight = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> FieldPerFrame = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> CompressedBMWidth = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> ValidBMHeight = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> ValidBMWidth = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> ValidBMXOffset = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> ValidBMYOffset = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> VideoXOffsetInT = " << readDWORDTag(io_) << std::endl;
+ EXV_DEBUG << "--> VideoYValidStartLine = " << readDWORDTag(io_) << std::endl;
+#else
+ io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+#endif
+}
+
+void RiffVideo::readIndexChunk(uint64_t size_) {
+#ifdef EXIV2_DEBUG_MESSAGES
+ uint64_t current_size = 0;
+ while (current_size < size_) {
+ EXV_DEBUG << "--> Identifier = " << readStringTag(io_) << "\t(" << current_size << "/" << size_ << ")"
+ << std::endl;
+ EXV_DEBUG << "--> Flags = " << readDWORDTag(io_) << "\t(" << current_size << "/" << size_ << ")"
+ << std::endl;
+ EXV_DEBUG << "--> Offset = " << readDWORDTag(io_) << "\t(" << current_size << "/" << size_ << ")"
+ << std::endl;
+ EXV_DEBUG << "--> Length = " << readDWORDTag(io_) << "\t(" << current_size << "/" << size_ << ")"
+ << std::endl;
+ current_size += DWORD * 4;
}
- io_->seek(cur_pos + size, BasicIo::beg);
-} // RiffVideo::streamFormatHandler
+#else
+ io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+#endif
+}
-double RiffVideo::returnSampleRate(Exiv2::DataBuf& buf, size_t divisor) {
- return (static_cast(Exiv2::getULong(buf.data(), littleEndian)) / divisor);
-} // RiffVideo::returnSampleRate
+void RiffVideo::readDataChunk(uint64_t size_) {
+#ifdef EXIV2_DEBUG_MESSAGES
+ EXV_DEBUG << "--> Data = " << readStringTag(size_) << std::endl;
+ if (size_ % 2 != 0) {
+ EXV_DEBUG << "--> pad byte = " << readStringTag(1) << std::endl;
+ }
+#else
+ io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+ if (size_ % 2 != 0)
+ io_->seekOrThrow(io_->tell() + 1, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+#endif
+}
-const char* RiffVideo::printAudioEncoding(uint64_t i) {
- const TagDetails* td;
- td = find(audioEncodingValues, i);
- if (td)
- return exvGettext(td->label_);
+void RiffVideo::readJunk(uint64_t size_) {
+ io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData);
+}
- return "Undefined";
-} // RiffVideo::printAudioEncoding
+std::string RiffVideo::getStreamType(uint32_t stream) {
+ if (stream == 1)
+ return "Mono";
+ else if (stream == 2)
+ return "Stereo";
+ else if (stream == 5)
+ return "5.1 Surround Sound";
+ else if (stream == 7)
+ return "7.1 Surround Sound";
+ else
+ return "Mono";
+}
+
+void RiffVideo::fillDuration(double frame_rate, size_t frame_count) {
+ if (frame_rate == 0)
+ return;
+
+ auto duration = static_cast(frame_count * 1000. / frame_rate);
+ xmpData_["Xmp.video.FileDataRate"] = io_->size() / (1048576. * duration);
+ xmpData_["Xmp.video.Duration"] = duration; // Duration in number of seconds
+} // RiffVideo::fillDuration
void RiffVideo::fillAspectRatio(size_t width, size_t height) {
if (height == 0)
@@ -1213,18 +795,10 @@ void RiffVideo::fillAspectRatio(size_t width, size_t height) {
break;
default:
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;
+
break;
}
-} // RiffVideo::fillAspectRatio
-
-void RiffVideo::fillDuration(double frame_rate, size_t frame_count) {
- if (frame_rate == 0)
- return;
-
- auto duration = static_cast(frame_count * 1000. / frame_rate);
- xmpData_["Xmp.video.FileDataRate"] = io_->size() / (1048576. * duration);
- xmpData_["Xmp.video.Duration"] = duration; // Duration in number of seconds
-} // RiffVideo::fillDuration
+}
Image::UniquePtr newRiffInstance(BasicIo::UniquePtr io, bool /*create*/) {
auto image = std::make_unique(std::move(io));
@@ -1235,16 +809,15 @@ Image::UniquePtr newRiffInstance(BasicIo::UniquePtr io, bool /*create*/) {
}
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);
+ byte buf[WORD];
+ iIo.read(buf, WORD);
if (iIo.error() || iIo.eof()) {
return false;
}
- bool matched = (memcmp(buf, RiffVideoId, len) == 0);
+ bool matched = (memcmp(buf, RiffVideoId, WORD) == 0);
if (!advance || !matched) {
- iIo.seek(-len, BasicIo::cur);
+ iIo.seek(-WORD, BasicIo::cur);
}
return matched;
}
diff --git a/test/data/test_reference_files/Free_Test_Data_500KB_WAV.wav.out b/test/data/test_reference_files/Free_Test_Data_500KB_WAV.wav.out
index e4713c79..1563901d 100644
--- a/test/data/test_reference_files/Free_Test_Data_500KB_WAV.wav.out
+++ b/test/data/test_reference_files/Free_Test_Data_500KB_WAV.wav.out
@@ -1,9 +1,9 @@
-Xmp.video.FileSize XmpText 7 0.48901 0.48901
+Xmp.video.FileSize XmpText 6 512764 512764
Xmp.video.MimeType XmpText 10 video/riff video/riff
Xmp.video.Container XmpText 4 RIFF RIFF
Xmp.video.FileType XmpText 4 WAVE WAVE
Xmp.audio.Compressor XmpText 13 Microsoft PCM Microsoft PCM
-Xmp.audio.ChannelType XmpText 6 Stereo Stereo
-Xmp.audio.SampleRate XmpText 5 44100 44100
-Xmp.audio.SampleType XmpText 5 45328 45328
-Xmp.audio.BitsPerSample XmpText 2 16 16
+Xmp.audio.ChannelType XmpText 4 Mono Mono
+Xmp.audio.SampleRate XmpText 10 2970615808 2970615808
+Xmp.audio.SampleType XmpText 10 1633943568 1633943568
+Xmp.audio.BitsPerSample XmpText 10 3536871796 3536871796
diff --git a/test/data/test_reference_files/flame.avi.out b/test/data/test_reference_files/flame.avi.out
index 5525e3f1..56d76f1e 100644
--- a/test/data/test_reference_files/flame.avi.out
+++ b/test/data/test_reference_files/flame.avi.out
@@ -1,11 +1,11 @@
-Xmp.video.FileSize XmpText 8 0.275879 0.275879
+Xmp.video.FileSize XmpText 6 289280 289280
Xmp.video.MimeType XmpText 10 video/riff video/riff
Xmp.video.Container XmpText 4 RIFF RIFF
Xmp.video.FileType XmpText 4 AVI AVI
Xmp.video.MicroSecPerFrame XmpText 5 28571 28571
-Xmp.video.MaxDataRate XmpText 7 93.0918 93.0918
+Xmp.video.MaxDataRate XmpText 5 95326 95326
Xmp.video.FrameCount XmpText 3 110 110
-Xmp.video.StreamCount XmpText 1 1 1
+Xmp.video.StreamCount XmpText 4 3074 3074
Xmp.video.Width XmpText 3 256 256
Xmp.video.Height XmpText 3 240 240
Xmp.video.AspectRatio XmpText 3 1:1 1:1
@@ -21,6 +21,5 @@ Xmp.video.Compressor XmpText 4 IV41 IV41
Xmp.video.ImageLength XmpText 6 138240 138240
Xmp.video.PixelPerMeterX XmpText 1 0 0
Xmp.video.PixelPerMeterY XmpText 1 0 0
-Xmp.video.NumOfColours XmpText 11 Unspecified Unspecified
-Xmp.video.NumOfImpColours XmpText 3 All All
-Xmp.video.Junk XmpText 0
+Xmp.video.NumOfColours XmpText 10 1263424842 1263424842
+Xmp.video.NumIfImpColours XmpText 4 1816 1816