Merge pull request #2458 from mohamedchebbii/TestVideoData

Rework Asf, Riff video, test data and fix OSS-Fuzz issues
main
Rosen Penev 2 years ago committed by GitHub
commit aa16a54a7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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
<a href="mailto:mail.abu.to@gmail.com">mail.abu.to@gmail.com</a>
@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"
@ -72,10 +48,29 @@ class EXIV2API AsfVideo : public Image {
[[nodiscard]] std::string mimeType() const override;
//@}
private:
static constexpr size_t ASF_TAG_SIZE = 0x4;
static constexpr size_t BUFF_MIN_SIZE = 0x8;
static constexpr size_t GUI_SIZE = 16;
static constexpr size_t GUID_SIZE = 37;
static constexpr size_t CODEC_TYPE_VIDEO = 1;
static constexpr size_t CODEC_TYPE_AUDIO = 2;
class HeaderReader {
DataBuf IdBuf_;
uint64_t size_;
uint64_t remaining_size_;
public:
explicit HeaderReader(BasicIo::UniquePtr& io);
[[nodiscard]] uint64_t getSize() const {
return size_;
}
[[nodiscard]] uint64_t getRemainingSize() const {
return remaining_size_;
}
[[nodiscard]] DataBuf& getId() {
return IdBuf_;
}
};
protected:
/*!
@ -83,15 +78,6 @@ class EXIV2API AsfVideo : public Image {
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 tv Pointer to current tag,
@param size Size of the data block used to store Tag Information.
*/
void tagDecoder(uint64_t size);
/*!
@brief Interpret File_Properties tag information, and save it in
the respective XMP container.
@ -112,27 +98,26 @@ class EXIV2API AsfVideo : public Image {
in the respective XMP container.
@param size Size of the data block used to store Tag Data.
*/
void contentDescription(uint64_t size);
void contentDescription();
/*!
@brief Interpret Extended_Stream_Properties tag information, and
save it in the respective XMP container.
@param size Size of the data block used to store Tag Data.
*/
void extendedStreamProperties(uint64_t size);
void extendedStreamProperties();
/*!
@brief Interpret Header_Extension tag information, and save it in
the respective XMP container.
@param size Size of the data block used to store Tag Data.
*/
void headerExtension(uint64_t size);
void headerExtension();
/*!
@brief Interpret Metadata, Extended_Content_Description,
Metadata_Library tag information, and save it in the respective
XMP container.
@param meta A default integer which helps to overload the function
for various Tags that have a similar method of decoding.
*/
void metadataHandler(int meta = 1);
void extendedContentDescription();
void DegradableJPEGMedia();
/*!
@brief Calculates Aspect Ratio of a video, and stores it in the
respective XMP container.
@ -140,12 +125,6 @@ class EXIV2API AsfVideo : public Image {
void aspectRatio();
private:
//! Variable to check the end of metadata traversing.
bool continueTraversing_;
//! Variable which stores current position of the read pointer.
uint64_t localPosition_;
//! Variable which stores current stream being processsed.
int streamNumber_;
//! Variable to store height and width of a video frame.
uint64_t height_, width_;
@ -165,7 +144,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_

@ -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
* along 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 {
// *****************************************************************************
@ -57,7 +33,6 @@ class EXIV2API RiffVideo : public Image {
//! @name Manipulators
//@{
void printStructure(std::ostream& out, PrintStructureOption option, size_t depth) override;
void readMetadata() override;
void writeMetadata() override;
//@}
@ -65,128 +40,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_ = 0;
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.
@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 tagDecoder(Exiv2::DataBuf& buf, size_t size);
void readAviHeader();
/*!
@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.
@brief Interpret stream header list element (strh), and save it in the respective XMP container.
*/
void junkHandler(size_t size);
void readStreamHeader();
/*!
@brief Interpret Stream tag information, and save it
in the respective XMP container.
@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 streamHandler(size_t size);
void readStreamFormat(uint64_t size_);
/*!
@brief Interpret Stream Format tag information, and save it
in the respective XMP container.
@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 streamFormatHandler(size_t size);
void readStreamData(uint64_t size_);
/*!
@brief Interpret Riff Header tag information, and save it
in the respective XMP container.
@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 aviHeaderTagsHandler(size_t size);
void StreamName(uint64_t size_);
/*!
@brief Interpret Riff List tag information, and save it
in the respective XMP container.
@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 listHandler(size_t size);
void readInfoListChunk(uint64_t size_);
/*!
@brief Interpret Riff Stream Data tag information, and save it
in the respective XMP container.
@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 streamDataTagHandler(size_t size);
/*!
@brief Interpret INFO tag information, and save it
in the respective XMP container.
*/
void infoTagsHandler();
void readMoviList(uint64_t size_);
/*!
@brief Interpret Nikon Tags related to Video information, and
save it in the respective XMP container.
*/
void nikonTagsHandler();
/*!
@brief Interpret OpenDML tag information, and save it
in the respective XMP container.
@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 odmlTagsHandler();
//! @brief Skips Particular Blocks of Metadata List.
void skipListData();
void readVPRPChunk(uint64_t size_);
/*!
@brief Interprets DateTimeOriginal tag or stream name tag
information, and save it in the respective XMP container.
@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.
@param i parameter used to overload function
*/
void dateTimeOriginal(size_t size, int i = 0);
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.
@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.
*/
[[nodiscard]] static double returnSampleRate(Exiv2::DataBuf& buf, size_t divisor = 1);
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.
@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 fillAspectRatio(size_t width = 1, size_t height = 1);
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.
@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);
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 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";
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 ";
//! Variable to check the end of metadata traversing.
bool continueTraversing_;
//! Variable which stores current stream being processsed.
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.
@ -197,5 +184,3 @@ EXIV2API Image::UniquePtr newRiffInstance(BasicIo::UniquePtr io, bool create);
EXIV2API bool isRiffType(BasicIo& iIo, bool advance);
} // namespace Exiv2
#endif // RIFFVIDEO_HPP_

@ -1,62 +1,27 @@
// ***************************************************************** -*- 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) <mail.abu.to@gmail.com>
History: 08-Aug-12, AB: created
Credits: See header file
*/
// *****************************************************************************
// SPDX-License-Identifier: GPL-2.0-or-later
// included header files
#include <iostream>
#include "config.h"
#include "asfvideo.hpp"
#include <iostream>
#include "basicio.hpp"
#include "convert.hpp"
#include "config.h"
#include "enforce.hpp"
#include "error.hpp"
#include "futils.hpp"
#include "helper_functions.hpp"
#include "tags.hpp"
#include "tags_int.hpp"
#include "types.hpp"
// + standard includes
#include <cassert>
#include <cctype>
#include <cstring>
// *****************************************************************************
// 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<std::string, std::string> GUIDReferenceTags = {
/// Top-level ASF object GUIDS
{"75B22630-668E-11CF-A6D9-00AA0062CE6C", "Header"},
{"75B22636-668E-11CF-A6D9-00AA0062CE6C", "Data"},
@ -148,63 +113,56 @@ 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"}};
constexpr const TagDetails filePropertiesTags[] = {{7, "Xmp.video.FileLength"}, {6, "Xmp.video.CreationDate"},
{5, "Xmp.video.DataPackets"}, {4, "Xmp.video.Duration"},
{3, "Xmp.video.SendDuration"}, {2, "Xmp.video.Preroll"},
{1, "Xmp.video.MaxBitRate"}};
constexpr const TagDetails contentDescriptionTags[] = {{0, "Xmp.video.Title"},
{1, "Xmp.video.Author"},
{2, "Xmp.video.Copyright"},
{3, "Xmp.video.Description"},
{4, "Xmp.video.Rating"}};
/*!
@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(const 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);
}
GUID[36] = '\0';
GUID[8] = GUID[13] = GUID[18] = GUID[23] = '-';
std::string getGUID(DataBuf& buf) {
std::string GUID(36, '-');
if (buf.size() >= 16) {
GUID.at(0) = returnHex(buf.data()[3] / 0x10);
GUID.at(1) = returnHex(buf.data()[3] % 0x10);
GUID.at(2) = returnHex(buf.data()[2] / 0x10);
GUID.at(3) = returnHex(buf.data()[2] % 0x10);
GUID.at(4) = returnHex(buf.data()[1] / 0x10);
GUID.at(5) = returnHex(buf.data()[1] % 0x10);
GUID.at(6) = returnHex(buf.data()[0] / 0x10);
GUID.at(7) = returnHex(buf.data()[0] % 0x10);
GUID.at(9) = returnHex(buf.data()[5] / 0x10);
GUID.at(10) = returnHex(buf.data()[5] % 0x10);
GUID.at(11) = returnHex(buf.data()[4] / 0x10);
GUID.at(12) = returnHex(buf.data()[4] % 0x10);
GUID.at(14) = returnHex(buf.data()[7] / 0x10);
GUID.at(15) = returnHex(buf.data()[7] % 0x10);
GUID.at(16) = returnHex(buf.data()[6] / 0x10);
GUID.at(17) = returnHex(buf.data()[6] % 0x10);
GUID.at(19) = returnHex(buf.data()[8] / 0x10);
GUID.at(20) = returnHex(buf.data()[8] % 0x10);
GUID.at(21) = returnHex(buf.data()[9] / 0x10);
GUID.at(22) = returnHex(buf.data()[9] % 0x10);
GUID.at(24) = returnHex(buf.data()[10] / 0x10);
GUID.at(25) = returnHex(buf.data()[10] % 0x10);
GUID.at(26) = returnHex(buf.data()[11] / 0x10);
GUID.at(27) = returnHex(buf.data()[11] % 0x10);
GUID.at(28) = returnHex(buf.data()[12] / 0x10);
GUID.at(29) = returnHex(buf.data()[12] % 0x10);
GUID.at(30) = returnHex(buf.data()[13] / 0x10);
GUID.at(31) = returnHex(buf.data()[13] % 0x10);
GUID.at(32) = returnHex(buf.data()[14] / 0x10);
GUID.at(33) = returnHex(buf.data()[14] % 0x10);
GUID.at(34) = returnHex(buf.data()[15] / 0x10);
GUID.at(35) = returnHex(buf.data()[15] % 0x10);
}
// Example of output 399595EC-8667-4E2D-8FDB-98814CE76C1E
return GUID;
}
/*!
@ -248,407 +206,267 @@ void AsfVideo::readMetadata() {
IoCloser closer(*io_);
clearMetadata();
continueTraversing_ = true;
io_->seek(0, BasicIo::beg);
height_ = width_ = 1;
xmpData()["Xmp.video.FileSize"] = io_->size() / 1048576.;
xmpData()["Xmp.video.FileName"] = io_->path();
xmpData()["Xmp.video.MimeType"] = mimeType();
while (continueTraversing_)
decodeBlock();
aspectRatio();
} // AsfVideo::readMetadata
void AsfVideo::decodeBlock() {
DataBuf buf(BUFF_MIN_SIZE + 1);
uint64_t size = 0;
uint64_t cur_pos = io_->tell();
byte guidBuf[GUI_SIZE];
io_->read(guidBuf, GUI_SIZE);
if (io_->eof()) {
continueTraversing_ = false;
return;
}
char GUID[GUID_SIZE] = ""; // the getGUID function write the GUID[36],
io_->read(buf.data(), BUFF_MIN_SIZE);
size = Util::getUint64_t(buf);
getGUID(guidBuf, GUID);
auto tv = Exiv2::find(GUIDReferenceTags, GUID);
if (tv) {
auto tagDecoder = [&](const Internal::TagVocabulary* tv, uint64_t size) {
uint64_t cur_pos = io_->tell();
DataBuf buf(1000);
unsigned long count = 0, tempLength = 0;
Exiv2::Value::UniquePtr v = Exiv2::Value::create(Exiv2::xmpSeq);
AsfVideo::HeaderReader::HeaderReader(BasicIo::UniquePtr& io) : IdBuf_(GUID) {
if (io->size() >= io->tell() + GUID + QWORD) {
IdBuf_ = io->read(GUID);
if (compareTag(exvGettext(tv->label_), "Header")) {
localPosition_ = 0;
io_->read(buf.data(), 4);
io_->read(buf.data(), 2);
while (localPosition_ < cur_pos + size)
decodeBlock();
size_ = readQWORDTag(io);
if (size_ >= GUID + QWORD)
remaining_size_ = size_ - GUID - QWORD;
}
}
else if (compareTag(exvGettext(tv->label_), "File_Properties"))
void AsfVideo::decodeBlock() {
HeaderReader header(io_);
std::string guid = getGUID(header.getId());
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);
io_->seekOrThrow(io_->tell() + BYTE * 2, BasicIo::beg,
ErrorCode::kerFailedToReadImageData); // skip two reserved tags
for (uint32_t i = 0; i < nb_headers; i++) {
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(tv->label_), "Stream_Properties"))
else if (tag->second == "Stream_Properties")
streamProperties();
else if (compareTag(exvGettext(tv->label_), "Metadata"))
metadataHandler(1);
else if (compareTag(exvGettext(tv->label_), "Extended_Content_Description"))
metadataHandler(2);
else if (compareTag(exvGettext(tv->label_), "Metadata_Library"))
metadataHandler(3);
else if (compareTag(exvGettext(tv->label_), "Codec_List"))
else if (tag->second == "Header_Extension")
headerExtension();
else if (tag->second == "Codec_List")
codecList();
else if (compareTag(exvGettext(tv->label_), "Content_Description"))
contentDescription(size);
else if (compareTag(exvGettext(tv->label_), "Extended_Stream_Properties"))
extendedStreamProperties(size);
else if (compareTag(exvGettext(tv->label_), "Header_Extension")) {
localPosition_ = 0;
headerExtension(size);
}
else if (compareTag(exvGettext(tv->label_), "Language_List")) {
std::memset(buf.data(), 0x0, buf.size());
io_->read(buf.data(), 2);
count = Exiv2::getUShort(buf.data(), littleEndian);
while (count--) {
std::memset(buf.data(), 0x0, buf.size());
io_->read(buf.data(), 1);
tempLength = static_cast<int>(buf.data()[0]);
io_->read(buf.data(), tempLength);
v->read(Util::toString16(buf));
}
xmpData().add(Exiv2::XmpKey("Xmp.video.TrackLang"), v.get());
else if (tag->second == "Extended_Content_Description")
extendedContentDescription();
else if (tag->second == "Content_Description")
contentDescription();
else if (tag->second == "Extended_Stream_Properties")
extendedStreamProperties();
else if (tag->second == "Degradable_JPEG_Media") {
DegradableJPEGMedia();
} else
io_->seekOrThrow(io_->tell() + others.getRemainingSize(), BasicIo::beg,
ErrorCode::kerFailedToReadImageData);
} else
io_->seekOrThrow(io_->tell() + others.getRemainingSize(), BasicIo::beg, ErrorCode::kerFailedToReadImageData);
}
io_->seek(cur_pos + size, BasicIo::beg);
localPosition_ = io_->tell();
}; // AsfVideo::tagDecoder
tagDecoder(tv, size - 24);
} else
io_->seek(cur_pos + size, BasicIo::beg);
io_->seekOrThrow(io_->tell() + header.getRemainingSize(), BasicIo::beg, ErrorCode::kerFailedToReadImageData);
localPosition_ = io_->tell();
} else
io_->seekOrThrow(io_->tell() + header.getRemainingSize(), BasicIo::beg, ErrorCode::kerFailedToReadImageData);
} // AsfVideo::decodeBlock
void AsfVideo::extendedStreamProperties(uint64_t size) {
uint64_t cur_pos = io_->tell(), avgTimePerFrame = 0;
DataBuf buf(BUFF_MIN_SIZE);
static int previousStream;
io_->seek(cur_pos + 48, BasicIo::beg);
void AsfVideo::extendedStreamProperties() {
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
io_->seek(io_->tell() + DWORD, BasicIo::beg); // ignore Initial Buffer Fullness
io_->seek(io_->tell() + DWORD, BasicIo::beg); // ignore Alternate Data Bitrate
io_->seek(io_->tell() + DWORD, BasicIo::beg); // ignore Alternate Buffer Size
io_->seek(io_->tell() + DWORD, BasicIo::beg); // ignore Alternate Initial Buffer Fullness
io_->seek(io_->tell() + DWORD, BasicIo::beg); // ignore Maximum Object Size
io_->seek(io_->tell() + DWORD, BasicIo::beg); // ignore Flags Buffer Size
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(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(io_);
if (stream_length)
io_->seek(io_->tell() + stream_length, BasicIo::beg); // ignore Stream name
}
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(io_);
if (ext_sys_info_length)
io_->seek(io_->tell() + ext_sys_info_length, BasicIo::beg); // ignore Extension System Info
}
} // AsfVideo::extendedStreamProperties
io_->read(buf.data(), 2);
streamNumber_ = Exiv2::getUShort(buf.data(), littleEndian);
void AsfVideo::DegradableJPEGMedia() {
uint32_t width = readDWORDTag(io_);
width_ = width;
xmpData_["Xmp.video.Width"] = width;
io_->read(buf.data(), 2);
io_->read(buf.data(), BUFF_MIN_SIZE);
avgTimePerFrame = Util::getUint64_t(buf);
uint32_t height = readDWORDTag(io_);
height_ = height;
xmpData_["Xmp.video.Height"] = height;
if (previousStream < streamNumber_ && avgTimePerFrame != 0)
xmpData()["Xmp.video.FrameRate"] = 10000000. / avgTimePerFrame;
io_->seek(io_->tell() + WORD * 3 /*3 Reserved*/, BasicIo::beg);
previousStream = streamNumber_;
io_->seek(cur_pos + size, BasicIo::beg);
} // AsfVideo::extendedStreamProperties
uint32_t interchange_data_length = readWORDTag(io_);
io_->seek(io_->tell() + interchange_data_length /*Interchange data*/, BasicIo::beg);
}
void AsfVideo::streamProperties() {
DataBuf streamTypedBuf = io_->read(GUID);
void AsfVideo::contentDescription(uint64_t size) {
const size_t pos = io_->tell();
size_t length[5];
for (size_t& i : length) {
byte buf[2];
io_->read(buf, 2);
if (io_->error() || io_->eof())
throw Error(ErrorCode::kerFailedToReadImageData);
i = getUShort(buf, littleEndian);
}
for (int i = 0; i < 5; ++i) {
DataBuf buf(length[i]);
std::memset(buf.data(), 0x0, buf.size());
io_->read(buf.data(), length[i]);
if (io_->error() || io_->eof())
throw Error(ErrorCode::kerFailedToReadImageData);
auto td = Exiv2::find(contentDescriptionTags, i);
assert(td);
std::string str(reinterpret_cast<const char*>(buf.data()), length[i]);
if (convertStringCharset(str, "UCS-2LE", "UTF-8")) {
xmpData()[td->label_] = str;
} else {
xmpData()[td->label_] = Util::toString16(buf);
}
}
if (io_->seek(pos + size, BasicIo::beg))
throw Error(ErrorCode::kerFailedToReadImageData);
} // AsfVideo::contentDescription
auto stream_type = getGUID(streamTypedBuf);
void AsfVideo::streamProperties() {
DataBuf buf(20);
byte guidBuf[GUI_SIZE];
int stream = 0;
enum streamTypeInfo { Audio = 1, Video = 2 };
io_->read(guidBuf, GUI_SIZE);
char streamType[GUID_SIZE] = "";
getGUID(guidBuf, streamType);
auto tv = Exiv2::find(GUIDReferenceTags, streamType);
io_->read(guidBuf, GUI_SIZE);
int stream = 0;
if (compareTag(exvGettext(tv->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(tv->label_), "Video_Media"))
else if (tag_stream_type->second == "Video_Media")
stream = Video;
io_->read(buf.data(), BUFF_MIN_SIZE);
io_->seek(io_->tell() + GUID, BasicIo::beg); // ignore Error Correction Type
uint64_t time_offset = readQWORDTag(io_);
if (stream == Video)
xmpData()["Xmp.video.TimeOffset"] = Util::getUint64_t(buf);
xmpData()["Xmp.video.TimeOffset"] = time_offset;
else if (stream == Audio)
xmpData()["Xmp.audio.TimeOffset"] = Util::getUint64_t(buf);
io_->read(buf.data(), BUFF_MIN_SIZE);
std::memset(buf.data(), 0x0, buf.size());
io_->read(buf.data(), 1);
streamNumber_ = static_cast<int>(buf.data()[0]) & 127;
io_->read(buf.data(), 5);
std::memset(buf.data(), 0x0, buf.size());
io_->read(buf.data(), 2);
size_t temp = Exiv2::getUShort(buf.data(), littleEndian);
if (stream == 2) {
xmpData()["Xmp.video.Width"] = temp;
width_ = temp;
} else if (stream == Audio) {
// todo xmpData()["Xmp.audio.Codec"]
}
xmpData()["Xmp.audio.TimeOffset"] = time_offset;
io_->read(buf.data(), 2);
temp = Exiv2::getUShort(buf.data(), littleEndian);
if (stream == Audio)
xmpData()["Xmp.audio.ChannelType"] = temp;
auto specific_data_length = readDWORDTag(io_);
auto correction_data_length = readDWORDTag(io_);
io_->read(buf.data(), 4);
temp = Exiv2::getULong(buf.data(), littleEndian);
if (stream == Video) {
xmpData()["Xmp.video.Height"] = temp;
height_ = temp;
} else if (stream == Audio) {
xmpData()["Xmp.audio.SampleRate"] = temp;
io_->seek(io_->tell() + WORD /*Flags*/ + DWORD /*Reserved*/ + specific_data_length + correction_data_length,
BasicIo::beg);
}
} // AsfVideo::streamProperties
void AsfVideo::codecList() {
DataBuf buf(200);
io_->read(buf.data(), GUI_SIZE);
std::memset(buf.data(), 0x0, buf.size());
io_->read(buf.data(), 4);
int codecCount = Exiv2::getULong(buf.data(), littleEndian), descLength = 0, codecType = 0;
while (codecCount--) {
std::memset(buf.data(), 0x0, buf.size());
io_->read(buf.data(), 2);
codecType = Exiv2::getUShort(buf.data(), littleEndian);
io_->read(buf.data(), 2);
descLength = Exiv2::getUShort(buf.data(), littleEndian) * 2;
io_->read(buf.data(), descLength);
if (codecType == 1)
xmpData()["Xmp.video.Codec"] = Util::toString16(buf);
else if (codecType == 2)
xmpData()["Xmp.audio.Compressor"] = Util::toString16(buf);
std::memset(buf.data(), 0x0, buf.size());
io_->read(buf.data(), 2);
descLength = Exiv2::getUShort(buf.data(), littleEndian) * 2;
io_->read(buf.data(), descLength);
if (codecType == 1)
xmpData()["Xmp.video.CodecDescription"] = Util::toString16(buf);
else if (codecType == 2)
xmpData()["Xmp.audio.CodecDescription"] = Util::toString16(buf);
std::memset(buf.data(), 0x0, buf.size());
io_->read(buf.data(), 2);
descLength = Exiv2::getUShort(buf.data(), littleEndian);
io_->read(buf.data(), descLength);
}
} // AsfVideo::codecList
io_->seek(io_->tell() + GUID /*reserved*/, BasicIo::beg);
auto entries_count = readDWORDTag(io_);
for (uint32_t i = 0; i < entries_count; i++) {
uint16_t codec_type = readWORDTag(io_) * 2;
std::string codec = (codec_type == 1) ? "Xmp.video" : "Xmp.audio";
void AsfVideo::headerExtension(uint64_t size) {
uint64_t cur_pos = io_->tell();
DataBuf buf(20);
io_->read(buf.data(), 18);
buf.data()[4] = '\0';
io_->read(buf.data(), 4);
uint16_t codec_name_length = readWORDTag(io_) * 2;
if (codec_name_length)
xmpData()[codec + std::string(".CodecName")] = readStringWcharTag(io_, codec_name_length);
while (localPosition_ < cur_pos + size)
decodeBlock();
uint16_t codec_desc_length = readWORDTag(io_);
if (codec_desc_length)
xmpData()[codec + std::string(".CodecDescription")] = readStringWcharTag(io_, codec_desc_length);
io_->seek(cur_pos + size, BasicIo::beg);
} // AsfVideo::headerExtension
void AsfVideo::metadataHandler(int meta) {
DataBuf buf(5000);
io_->read(buf.data(), 2);
uint16_t recordCount = Exiv2::getUShort(buf.data(), littleEndian), nameLength = 0, dataLength = 0, dataType = 0;
Exiv2::Value::UniquePtr v = Exiv2::Value::create(Exiv2::xmpSeq);
byte guidBuf[GUI_SIZE];
char fileID[GUID_SIZE] = "";
while (recordCount--) {
std::memset(buf.data(), 0x0, buf.size());
if (meta == 1 || meta == 3) {
io_->read(buf.data(), 4);
io_->read(buf.data(), 2);
nameLength = Exiv2::getUShort(buf.data(), littleEndian);
io_->read(buf.data(), 2);
dataType = Exiv2::getUShort(buf.data(), littleEndian);
io_->read(buf.data(), 4);
dataLength = Exiv2::getULong(buf.data(), littleEndian);
if (nameLength > 5000) {
#ifndef SUPPRESS_WARNINGS
EXV_ERROR << "Xmp.video.Metadata nameLength was found to be larger than 5000 "
<< " entries considered invalid; not read.\n";
#endif
io_->seek(io_->tell() + nameLength, BasicIo::beg);
} else {
io_->read(buf.data(), nameLength);
uint16_t codec_info_length = readWORDTag(io_);
Internal::enforce(codec_info_length && codec_info_length + io_->tell() < io_->size(),
Exiv2::ErrorCode::kerCorruptedMetadata);
xmpData()[codec + std::string(".CodecInfo")] = readStringTag(io_, codec_info_length);
}
} // AsfVideo::codecList
v->read(Util::toString16(buf));
if (dataType == 6) {
io_->read(guidBuf, GUI_SIZE);
getGUID(guidBuf, fileID);
} else {
// Sanity check with an "unreasonably" large number
if (dataLength > 5000) {
#ifndef SUPPRESS_WARNINGS
EXV_ERROR << "Xmp.video.Metadata dataLength was found to be larger than 5000 "
<< " entries considered invalid; not read.\n";
#endif
io_->seek(io_->tell() + dataLength, BasicIo::beg);
} else
io_->read(buf.data(), dataLength);
void AsfVideo::headerExtension() {
io_->seek(io_->tell() + GUID /*reserved1*/ + WORD /*Reserved2*/, BasicIo::beg);
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(io_);
std::string value;
for (uint16_t i = 0; i < content_descriptor_count; i++) {
uint16_t descriptor_name_length = readWORDTag(io_);
if (descriptor_name_length)
value += readStringWcharTag(io_, descriptor_name_length); // Descriptor Name
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(": ") + readStringWcharTag(io_, descriptor_value_length);
break;
case 1 /*BYTE array */:
value += std::string(": ") + readStringTag(io_, descriptor_value_length);
break;
case 2 /*BOOL*/:
value += std::string(": ") + std::to_string(readWORDTag(io_));
break;
case 3 /*DWORD */:
value += std::string(": ") + std::to_string(readDWORDTag(io_));
break;
case 4 /*QWORD */:
value += std::string(": ") + std::to_string(readQWORDTag(io_));
break;
case 5 /*WORD*/:
value += std::string(": ") + std::to_string(readWORDTag(io_));
;
break;
}
}
else if (meta == 2) {
io_->read(buf.data(), 2);
nameLength = Exiv2::getUShort(buf.data(), littleEndian);
if (nameLength > 5000) {
#ifndef SUPPRESS_WARNINGS
EXV_ERROR << "Xmp.video.Metadata nameLength was found to be larger than 5000 "
<< " entries considered invalid; not read.\n";
#endif
io_->seek(io_->tell() + nameLength, BasicIo::beg);
} else {
io_->read(buf.data(), nameLength);
value += std::string(", ");
}
v->read(Util::toString16(buf));
io_->read(buf.data(), 2);
dataType = Exiv2::getUShort(buf.data(), littleEndian);
xmpData()["Xmp.video.ExtendedContentDescription"] = value;
} // AsfVideo::extendedContentDescription
io_->read(buf.data(), 2);
dataLength = Exiv2::getUShort(buf.data(), littleEndian);
void AsfVideo::contentDescription() {
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_);
// Sanity check with an "unreasonably" large number
if (dataLength > 5000) {
#ifndef SUPPRESS_WARNINGS
EXV_ERROR << "Xmp.video.Metadata dataLength was found to be larger than 5000 "
<< " entries considered invalid; not read.\n";
#endif
io_->seek(io_->tell() + dataLength, BasicIo::beg);
} else
io_->read(buf.data(), dataLength);
}
if (title_length)
xmpData()["Xmp.video.Title"] = readStringWcharTag(io_, title_length);
if (dataType == 0) { // Unicode String
v->read(Util::toString16(buf));
} else if (dataType == 2 || dataType == 5) { // 16-bit Unsigned Integer
v->read(Exiv2::toString(Exiv2::getUShort(buf.data(), littleEndian)));
} else if (dataType == 3) { // 32-bit Unsigned Integer
v->read(Exiv2::toString(Exiv2::getULong(buf.data(), littleEndian)));
} else if (dataType == 4) { // 64-bit Unsigned Integer
v->read(Exiv2::toString(Util::getUint64_t(buf)));
} else if (dataType == 6) { // 128-bit GUID
v->read(Exiv2::toString(fileID));
} else { // Byte array
v->read(Exiv2::toString(buf.data()));
}
}
if (author_length)
xmpData()["Xmp.video.Author"] = readStringWcharTag(io_, author_length);
if (meta == 1) {
xmpData().add(Exiv2::XmpKey("Xmp.video.Metadata"), v.get());
} else if (meta == 2) {
xmpData().add(Exiv2::XmpKey("Xmp.video.ExtendedContentDescription"), v.get());
} else {
xmpData().add(Exiv2::XmpKey("Xmp.video.MetadataLibrary"), v.get());
}
} // AsfVideo::metadataHandler
void AsfVideo::fileProperties() {
DataBuf buf(BUFF_MIN_SIZE);
if (copyright_length)
xmpData()["Xmp.video.Copyright"] = readStringWcharTag(io_, copyright_length);
byte guidBuf[GUI_SIZE];
io_->read(guidBuf, GUI_SIZE);
char fileID[GUID_SIZE] = "";
int count = 7;
getGUID(guidBuf, fileID);
xmpData()["Xmp.video.FileID"] = fileID;
if (desc_length)
xmpData()["Xmp.video.Description"] = readStringWcharTag(io_, desc_length);
const TagDetails* td;
if (rating_length)
xmpData()["Xmp.video.Rating"] = readStringWcharTag(io_, rating_length);
while (count--) {
td = Exiv2::find(filePropertiesTags, (count + 1));
io_->read(buf.data(), BUFF_MIN_SIZE);
} // AsfVideo::extendedContentDescription
if (count == 0) {
buf.data()[4] = '\0';
io_->read(buf.data(), 4);
io_->read(buf.data(), 4);
}
if (count == 3 || count == 2) {
xmpData()[exvGettext(td->label_)] = Util::getUint64_t(buf) / 10000;
} else {
xmpData()[exvGettext(td->label_)] = Util::getUint64_t(buf);
}
}
void AsfVideo::fileProperties() {
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(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<double>(width_) / height_;
aspectRatio = floor(aspectRatio * 10) / 10;
xmpData()["Xmp.video.AspectRatio"] = aspectRatio;
@ -692,9 +510,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;

@ -3,7 +3,10 @@
#include "helper_functions.hpp"
#include <cmath>
#include <codecvt>
#include <cstring>
#include <locale>
#include "enforce.hpp"
std::string string_from_unterminated(const char* data, size_t data_length) {
if (data_length == 0) {
@ -13,35 +16,53 @@ 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<char>(n + 48);
return static_cast<char>(n + 55);
}
std::string toString16(Exiv2::DataBuf& buf) {
std::ostringstream os;
char t;
std::string utf16ToUtf8(const std::wstring& wstr) {
using convert_typeX = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_typeX, wchar_t> converterX;
for (size_t i = 0; i <= buf.size(); i += 2) {
t = buf.data()[i] + 16 * buf.data()[i + 1];
if (t == 0) {
if (i)
os << '\0';
break;
}
os << t;
}
return os.str();
std::string str = converterX.to_bytes(wstr);
str.erase(std::remove(str.begin(), str.end(), '\0'), str.end());
return str;
}
uint64_t readQWORDTag(BasicIo::UniquePtr& io) {
Internal::enforce(QWORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf = io->read(QWORD);
return FieldBuf.read_uint64(0, littleEndian);
}
uint64_t getUint64_t(Exiv2::DataBuf& buf) {
uint64_t temp = 0;
uint32_t readDWORDTag(BasicIo::UniquePtr& io) {
Internal::enforce(DWORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf = io->read(DWORD);
return FieldBuf.read_uint32(0, littleEndian);
}
for (int i = 0; i < 8; ++i) {
temp = temp + static_cast<uint64_t>(buf.data()[i] * (pow(static_cast<float>(256), i)));
}
return temp;
uint16_t readWORDTag(BasicIo::UniquePtr& io) {
Internal::enforce(WORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf = io->read(WORD);
return FieldBuf.read_uint16(0, littleEndian);
}
} // namespace Util
std::string readStringWcharTag(BasicIo::UniquePtr& io, size_t length) {
Internal::enforce(length <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf(length + 1);
io->readOrThrow(FieldBuf.data(), length, ErrorCode::kerFailedToReadImageData);
std::wstring wst(FieldBuf.begin(), FieldBuf.end());
return utf16ToUtf8(wst);
}
std::string readStringTag(BasicIo::UniquePtr& io, size_t length) {
Internal::enforce(length <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf(length + 1);
io->readOrThrow(FieldBuf.data(), length, ErrorCode::kerFailedToReadImageData);
return Exiv2::toString(FieldBuf.data()).substr(0, length);
}
} // namespace Exiv2

@ -4,6 +4,7 @@
#define HELPER_FUNCTIONS_HPP
#include <string>
#include "basicio.hpp"
#include "types.hpp"
/*!
@brief Convert a (potentially not null terminated) array into a
@ -22,24 +23,42 @@
*/
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);
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;
// @brief
/*!
@brief Function used to read data from data buffer, reads 16-bit character
array and stores it in std::string object.
@param buf Exiv2 data buffer, which stores the information
@return Returns std::string object .
*/
std::string toString16(Exiv2::DataBuf& buf);
@brief The function utf16ToUtf8 takes a wide string wstr as input and converts it to a narrow string
The conversion is performed using the std::wstring_convert class template and a std::codecvt_utf8 facet, which
implements conversion between UTF-8 and wide characters.
@param wstr : wide string
@return Returns std::string object
*/
std::string utf16ToUtf8(const std::wstring& wstr);
[[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, size_t length);
[[nodiscard]] std::string readStringTag(Exiv2::BasicIo::UniquePtr& io, size_t length = DWORD);
//! Function used to convert buffer data into 64-bit Integer, information stored in littleEndian format
uint64_t getUint64_t(Exiv2::DataBuf& buf);
} // namespace Util
} // namespace Exiv2
#endif // HELPER_FUNCTIONS_HPP

@ -600,7 +600,6 @@ void MatroskaVideo::readMetadata() {
continueTraversing_ = true;
height_ = width_ = 1;
xmpData_["Xmp.video.FileName"] = io_->path();
xmpData_["Xmp.video.FileSize"] = io_->size() / bytesMB;
xmpData_["Xmp.video.MimeType"] = mimeType();

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,9 @@
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 4 Mono Mono
Xmp.audio.SampleRate XmpText 10 2970615808 2970615808
Xmp.audio.SampleType XmpText 10 1633943568 1633943568
Xmp.audio.BitsPerSample XmpText 10 3536871796 3536871796

@ -0,0 +1,26 @@
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 5 95326 95326
Xmp.video.FrameCount XmpText 3 110 110
Xmp.audio.ChannelType XmpText 4 Mono Mono
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
Xmp.video.FileDataRate XmpText 11 8.78036e-05 8.78036e-05
Xmp.video.Duration XmpText 4 3142 3142
Xmp.video.Codec XmpText 4 cvid cvid
Xmp.video.FrameRate XmpText 2 35 35
Xmp.video.VideoQuality XmpText 1 0 0
Xmp.video.VideoSampleSize XmpText 1 0 0
Xmp.video.Planes XmpText 1 1 1
Xmp.video.PixelDepth XmpText 2 24 24
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 10 1263424842 1263424842
Xmp.video.NumIfImpColours XmpText 4 1816 1816

@ -0,0 +1,50 @@
Xmp.video.FileSize XmpText 8 0.548162 0.548162
Xmp.video.MimeType XmpText 15 video/quicktime video/quicktime
Xmp.video.MajorBrand XmpText 25 Apple QuickTime (.MOV/QT) Apple QuickTime (.MOV/QT)
Xmp.video.MinorVersion XmpText 3 512 512
Xmp.video.CompatibleBrands XmpSeq 1 Apple QuickTime (.MOV/QT) Apple QuickTime (.MOV/QT)
Xmp.video.MovieHeaderVersion XmpText 1 0 0
Xmp.video.DateUTC XmpText 1 0 0
Xmp.video.ModificationDate XmpText 1 0 0
Xmp.video.TimeScale XmpText 4 1000 1000
Xmp.video.Duration XmpText 5 13347 13347
Xmp.video.PreferredRate XmpText 1 1 1
Xmp.video.PreferredVolume XmpText 3 100 100
Xmp.video.PreviewTime XmpText 1 0 0
Xmp.video.PreviewDuration XmpText 1 0 0
Xmp.video.PosterTime XmpText 1 0 0
Xmp.video.SelectionTime XmpText 1 0 0
Xmp.video.SelectionDuration XmpText 1 0 0
Xmp.video.CurrentTime XmpText 1 0 0
Xmp.video.NextTrackID XmpText 1 2 2
Xmp.video.TrackHeaderVersion XmpText 1 0 0
Xmp.video.TrackCreateDate XmpText 1 0 0
Xmp.video.TrackModifyDate XmpText 1 0 0
Xmp.video.TrackID XmpText 1 1 1
Xmp.video.TrackDuration XmpText 2 13 13
Xmp.video.TrackLayer XmpText 1 0 0
Xmp.video.TrackVolume XmpText 1 0 0
Xmp.video.Width XmpText 3 640 640
Xmp.video.Height XmpText 3 360 360
Xmp.video.MediaHeaderVersion XmpText 1 0 0
Xmp.video.MediaCreateDate XmpText 1 0 0
Xmp.video.MediaModifyDate XmpText 1 0 0
Xmp.video.MediaTimeScale XmpText 5 30000 30000
Xmp.video.MediaDuration XmpText 2 13 13
Xmp.video.MediaLangCode XmpText 1 0 0
Xmp.video.HandlerClass XmpText 12 Data Handler Data Handler
Xmp.video.HandlerType XmpText 3 URL URL
Xmp.video.GraphicsMode XmpText 7 srcCopy srcCopy
Xmp.video.OpColor XmpText 1 0 0
Xmp.video.URL XmpText 0
Xmp.video.Codec XmpText 39 MP4 Base w/ AVC ext [ISO 14496-12:2005] MP4 Base w/ AVC ext [ISO 14496-12:2005]
Xmp.video.VendorID XmpText 6 FFmpeg FFmpeg
Xmp.video.SourceImageWidth XmpText 3 640 640
Xmp.video.SourceImageHeight XmpText 3 360 360
Xmp.video.XResolution XmpText 2 72 72
Xmp.video.YResolution XmpText 2 72 72
Xmp.video.Compressor XmpText 22 Lavc57.107.100 libx264 Lavc57.107.100 libx264
Xmp.video.BitDepth XmpText 2 24 24
Xmp.video.FrameRate XmpText 8 0.999001 0.999001
Xmp.video.SoftwareVersion XmpText 13 Lavf57.83.100 Lavf57.83.100
Xmp.video.AspectRatio XmpText 4 16:9 16:9

@ -0,0 +1,15 @@
Xmp.video.FileSize XmpText 8 0.553182 0.553182
Xmp.video.MimeType XmpText 9 video/asf video/asf
Xmp.video.FileID XmpText 36 00000000-0000-0000-0000-000000000000 00000000-0000-0000-0000-000000000000
Xmp.video.FileLength XmpText 6 580053 580053
Xmp.video.CreationDate XmpText 18 116444736000000000 116444736000000000
Xmp.video.DataPackets XmpText 3 181 181
Xmp.video.duration XmpText 9 164460000 164460000
Xmp.video.SendDuration XmpText 9 133460000 133460000
Xmp.video.Preroll XmpText 4 3100 3100
Xmp.video.MaxBitRate XmpText 6 200000 200000
Xmp.video.ExtendedContentDescription XmpSeq 1 major_brand: mp42, minor_version: 0, compatible_brands: mp42mp41isomavc1, WM/EncodingSettings: Lavf57.83.100, major_brand: mp42, minor_version: 0, compatible_brands: mp42mp41isomavc1, WM/EncodingSettings: Lavf57.83.100,
Xmp.video.TimeOffset XmpText 1 0 0
Xmp.audio.CodecName XmpText 9 msmpeg4v3 msmpeg4v3
Xmp.audio.CodecInfo XmpText 4 MP43 MP43
Xmp.video.AspectRatio XmpText 3 1:1 1:1

@ -29,6 +29,11 @@ def get_valid_files(data_dir):
".webp",
".xmp",
".mp4",
".asf",
".avi",
".mkv",
".wav",
".mov"
]
excludes = [

Loading…
Cancel
Save