Skip to content

Commit

Permalink
1748 Video Support in V1.0: part 1/3 : support MatroskaViedo (#2413)
Browse files Browse the repository at this point in the history
* 1748 Video Support in V1.0: part 1/3 : support MatroskaViedo

* Simplify the code of matroskavideo

* protect conevrtuint64 method from overflow

* use size_t instead of uint64_t
  • Loading branch information
mohamedchebbii authored Dec 30, 2022
1 parent 9ca161d commit 1280f3b
Show file tree
Hide file tree
Showing 8 changed files with 1,236 additions and 2 deletions.
4 changes: 2 additions & 2 deletions exiv2.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ and see if `enable_bmff=1`.
- Naked codestream JXL files do not contain Exif, IPTC or XMP metadata.

- Support of video files is limited. Currently **exiv2** only has some
rudimentary support to read metadata from quicktime based video files (e.g.
.MOV/.MP4).
rudimentary support to read metadata from quicktime and matroskavideo based video files (e.g.
.MOV/.MP4, MKV)


[TOC](#TOC)
Expand Down
1 change: 1 addition & 0 deletions include/exiv2/image_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ enum class ImageType {
webp,
xmp, ///< XMP sidecar files
qtime,
mkv,
};
} // namespace Exiv2

Expand Down
196 changes: 196 additions & 0 deletions include/exiv2/matroskavideo.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// ***************************************************************** -*- 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.
*/
#ifndef MATROSKAVIDEO_HPP_
#define MATROSKAVIDEO_HPP_

// *****************************************************************************
#include "exiv2lib_export.h"

// included header files
#include "image.hpp"

// *****************************************************************************
// namespace extensions
namespace Exiv2 {

/*!
@brief Helper structure for the Matroska tags lookup table.
*/

// *****************************************************************************
// class definitions
namespace Internal {

enum matroskaTypeEnum : char {
String = 's',
Integer = 'i',
UInteger = 'u',
Date = 'd',
InternalField = 'n',
Boolean = 'o',
Binary = 'b',
Master = 'm',
Float = 'f',
Utf8 = '8',
UndefinedType = 'z'

};

enum matroskaProcessEnum : char { Process = 'p', Skip = 's', Composite = 'c', Undefined = 'u' };

struct MatroskaTag {
uint64_t _id;
std::string _label;
matroskaTypeEnum _type;
matroskaProcessEnum _process;

MatroskaTag(uint64_t id, const std::string& label, matroskaTypeEnum type, matroskaProcessEnum process) :
_id(id), _label(label), _type(type), _process(process) {
}

MatroskaTag(uint64_t id, const std::string& label) :
_id(id), _label(label), _type(matroskaTypeEnum::UndefinedType), _process(matroskaProcessEnum::Undefined) {
}

bool isSkipped() const {
return _process == Skip;
}
bool isComposite() const {
return _process == Composite;
}
void dump(std::ostream& os) const {
os << " MatroskaTag "
<< " id: [0x" << std::hex << _id << "] label:[" << _label << "] type:[" << _type << "] process :[" << _process
<< "]\n";
}
};

/// @brief Utility function to search into std::array of pairs
/// @return the searched pair if exist,else nullptr
template <size_t N>
[[nodiscard]] const MatroskaTag* findTag(const std::array<MatroskaTag, N>& src, const uint64_t& key) {
const auto rc = std::find_if(src.begin(), src.end(), [&key](const MatroskaTag& tag) { return tag._id == key; });
// the return value is of type "const MatroskaTag*", so we return the adress of the content of the input
// iterator return by find_if
return rc == std::end(src) ? nullptr : &(*rc);
}

} // namespace Internal

/*!
@brief Class to access Matroska video files.
*/
class EXIV2API MatroskaVideo : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor for a Matroska video. Since the constructor
can not return a result, callers should check the good() method
after object construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
explicit MatroskaVideo(BasicIo::UniquePtr io);

//! Copy constructor
MatroskaVideo(const MatroskaVideo& rhs) = delete;
//! Assignment operator
MatroskaVideo& operator=(const MatroskaVideo& rhs) = delete;
//@}

//! @name Manipulators
//@{
void readMetadata() override;
void writeMetadata() override;
//@}

//! @name Accessors
//@{
[[nodiscard]] std::string mimeType() const override;
//@}

protected:
/*!
@brief Function used to calulate the size of a block.
This information is only stored in one byte.
The size of the block is calculated by counting
the number of leading zeros in the binary code of the byte.
Size = (No. of leading zeros + 1) bytes
@param b The byte, which stores the information to calculate the size
@return Return the size of the block.
*/
[[nodiscard]] uint32_t findBlockSize(byte b);
/*!
@brief Check for a valid tag and decode the block at the current IO position.
Calls contentManagement() or skips to next tag, if required.
*/
void decodeBlock();
/*!
@brief Interpret tag information, and save it in the respective XMP container.
@param mt Pointer to current tag,
@param buf Pointer to the memory area with the tag information.
@param size Size of \em buf.
*/

void decodeInternalTags(const Internal::MatroskaTag* tag, const byte* buf, size_t size);
void decodeStringTags(const Internal::MatroskaTag* tag, const byte* buf);
void decodeIntegerTags(const Internal::MatroskaTag* tag, const byte* buf, size_t size);
void decodeBooleanTags(const Internal::MatroskaTag* tag, const byte* buf, size_t size);
void decodeDateTags(const Internal::MatroskaTag* tag, const byte* buf, size_t size);
void decodeFloatTags(const Internal::MatroskaTag* tag, const byte* buf, size_t size);
/*!Internal::
@brief Calculates Aspect Ratio of a video, and stores it in the
respective XMP container.
*/
void aspectRatio();

private:
//! Variable to check the end of metadata traversing.
bool continueTraversing_;
//! Variable to store height and width of a video frame.
uint64_t height_;
uint64_t width_;
uint32_t track_count_;
double time_code_scale_ = 1.0;
uint64_t stream_ = 0;

static constexpr double bytesMB = 1048576;

}; // class MatroskaVideo

// *****************************************************************************
/*!
@brief Create a new MatroskaVideo instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
EXIV2API Image::UniquePtr newMkvInstance(BasicIo::UniquePtr io, bool create);

//! Check if the file iIo is a Matroska Video.
EXIV2API bool isMkvType(BasicIo& iIo, bool advance);

} // namespace Exiv2

#endif // #ifndef MATROSKAVIDEO_HPP_
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ set(PUBLIC_HEADERS
../include/exiv2/iptc.hpp
../include/exiv2/jp2image.hpp
../include/exiv2/jpgimage.hpp
../include/exiv2/matroskavideo.hpp
../include/exiv2/metadatum.hpp
../include/exiv2/mrwimage.hpp
../include/exiv2/orfimage.hpp
Expand Down Expand Up @@ -105,6 +106,7 @@ add_library( exiv2lib
iptc.cpp
jp2image.cpp
jpgimage.cpp
matroskavideo.cpp
metadatum.cpp
mrwimage.cpp
orfimage.cpp
Expand Down
3 changes: 3 additions & 0 deletions src/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "bmpimage.hpp"
#include "gifimage.hpp"
#include "jp2image.hpp"
#include "matroskavideo.hpp"
#include "nikonmn_int.hpp"
#include "orfimage.hpp"
#include "pgfimage.hpp"
Expand Down Expand Up @@ -100,6 +101,8 @@ constexpr auto registry = std::array{
// needs to be before bmff because some ftyp files are handled as qt and
// the rest should fall through to bmff
Registry{ImageType::qtime, newQTimeInstance, isQTimeType, amRead, amNone, amRead, amNone},
Registry{ImageType::mkv, newMkvInstance, isMkvType, amRead, amNone, amRead, amNone},

#ifdef EXV_ENABLE_BMFF
Registry{ImageType::bmff, newBmffInstance, isBmffType, amRead, amRead, amRead, amNone},
#endif // EXV_ENABLE_BMFF
Expand Down
Loading

0 comments on commit 1280f3b

Please sign in to comment.