Merge pull request #2458 from mohamedchebbii/TestVideoData
Rework Asf, Riff video, test data and fix OSS-Fuzz issues
This commit is contained in:
commit
aa16a54a7f
@ -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_
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
// *****************************************************************************
|
||||
#include "exiv2lib_export.h"
|
||||
|
||||
// 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:
|
||||
/*!
|
||||
@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 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 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 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 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 INFO tag information, and save it
|
||||
in the respective XMP container.
|
||||
*/
|
||||
void infoTagsHandler();
|
||||
/*!
|
||||
@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.
|
||||
*/
|
||||
void odmlTagsHandler();
|
||||
//! @brief Skips Particular Blocks of Metadata List.
|
||||
void skipListData();
|
||||
/*!
|
||||
@brief Interprets DateTimeOriginal tag or stream name tag
|
||||
information, and save it in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
@param i parameter used to overload function
|
||||
*/
|
||||
void dateTimeOriginal(size_t size, int i = 0);
|
||||
/*!
|
||||
@brief Calculates Sample Rate of a particular stream.
|
||||
@param buf Data buffer with the dividend.
|
||||
@param divisor The Divisor required to calculate sample rate.
|
||||
@return Return the sample rate of the stream.
|
||||
*/
|
||||
[[nodiscard]] static double returnSampleRate(Exiv2::DataBuf& buf, size_t divisor = 1);
|
||||
/*!
|
||||
@brief Calculates Aspect Ratio of a video, and stores it in the
|
||||
respective XMP container.
|
||||
@param width Width of the video.
|
||||
@param height Height of the video.
|
||||
*/
|
||||
void fillAspectRatio(size_t width = 1, size_t height = 1);
|
||||
/*!
|
||||
@brief Calculates Duration of a video, and stores it in the
|
||||
respective XMP container.
|
||||
@param frame_rate Frame rate of the video.
|
||||
@param frame_count Total number of frames present in the video.
|
||||
*/
|
||||
void fillDuration(double frame_rate, size_t frame_count);
|
||||
class HeaderReader {
|
||||
std::string id_ = "";
|
||||
uint64_t size_ = 0;
|
||||
|
||||
[[nodiscard]] static bool equalsRiffTag(Exiv2::DataBuf& buf, const char* str);
|
||||
public:
|
||||
explicit HeaderReader(BasicIo::UniquePtr& io);
|
||||
|
||||
static void copyTagValue(DataBuf& buf_dest, DataBuf& buf_src, size_t index = RIFF_TAG_SIZE);
|
||||
[[nodiscard]] uint64_t getSize() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string& getId() {
|
||||
return id_;
|
||||
}
|
||||
};
|
||||
|
||||
void readList(HeaderReader& header_);
|
||||
|
||||
void readChunk(HeaderReader& header_);
|
||||
|
||||
void decodeBlocks();
|
||||
|
||||
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.
|
||||
bool equal(const std::string& str1, const std::string& str2);
|
||||
|
||||
/*!
|
||||
@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 header list element (strh), and save it in the respective XMP container.
|
||||
*/
|
||||
void readStreamHeader();
|
||||
|
||||
/*!
|
||||
@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 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 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 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 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 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 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 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 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.
|
||||
*/
|
||||
void fillDuration(double frame_rate, size_t frame_count);
|
||||
|
||||
/*!
|
||||
@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";
|
||||
|
||||
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_
|
||||
|
||||
691
src/asfvideo.cpp
691
src/asfvideo.cpp
@ -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);
|
||||
|
||||
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);
|
||||
}
|
||||
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] = '-';
|
||||
|
||||
// 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();
|
||||
decodeBlock();
|
||||
|
||||
aspectRatio();
|
||||
} // AsfVideo::readMetadata
|
||||
|
||||
void AsfVideo::decodeBlock() {
|
||||
DataBuf buf(BUFF_MIN_SIZE + 1);
|
||||
uint64_t size = 0;
|
||||
uint64_t cur_pos = io_->tell();
|
||||
AsfVideo::HeaderReader::HeaderReader(BasicIo::UniquePtr& io) : IdBuf_(GUID) {
|
||||
if (io->size() >= io->tell() + GUID + QWORD) {
|
||||
IdBuf_ = io->read(GUID);
|
||||
|
||||
byte guidBuf[GUI_SIZE];
|
||||
io_->read(guidBuf, GUI_SIZE);
|
||||
|
||||
if (io_->eof()) {
|
||||
continueTraversing_ = false;
|
||||
return;
|
||||
size_ = readQWORDTag(io);
|
||||
if (size_ >= GUID + QWORD)
|
||||
remaining_size_ = size_ - GUID - QWORD;
|
||||
}
|
||||
}
|
||||
|
||||
char GUID[GUID_SIZE] = ""; // the getGUID function write the GUID[36],
|
||||
void AsfVideo::decodeBlock() {
|
||||
HeaderReader header(io_);
|
||||
std::string guid = getGUID(header.getId());
|
||||
|
||||
io_->read(buf.data(), BUFF_MIN_SIZE);
|
||||
size = Util::getUint64_t(buf);
|
||||
auto tv = GUIDReferenceTags.find(guid);
|
||||
if (tv != GUIDReferenceTags.end()) {
|
||||
if (tv->second == "Header") {
|
||||
DataBuf nbHeadersBuf(DWORD + 1);
|
||||
io_->read(nbHeadersBuf.data(), DWORD);
|
||||
|
||||
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);
|
||||
|
||||
if (compareTag(exvGettext(tv->label_), "Header")) {
|
||||
localPosition_ = 0;
|
||||
io_->read(buf.data(), 4);
|
||||
io_->read(buf.data(), 2);
|
||||
|
||||
while (localPosition_ < cur_pos + size)
|
||||
decodeBlock();
|
||||
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 (tag->second == "Stream_Properties")
|
||||
streamProperties();
|
||||
else if (tag->second == "Header_Extension")
|
||||
headerExtension();
|
||||
else if (tag->second == "Codec_List")
|
||||
codecList();
|
||||
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);
|
||||
}
|
||||
} else
|
||||
io_->seekOrThrow(io_->tell() + header.getRemainingSize(), BasicIo::beg, ErrorCode::kerFailedToReadImageData);
|
||||
|
||||
else if (compareTag(exvGettext(tv->label_), "File_Properties"))
|
||||
fileProperties();
|
||||
|
||||
else if (compareTag(exvGettext(tv->label_), "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"))
|
||||
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());
|
||||
}
|
||||
|
||||
io_->seek(cur_pos + size, BasicIo::beg);
|
||||
localPosition_ = io_->tell();
|
||||
}; // AsfVideo::tagDecoder
|
||||
|
||||
tagDecoder(tv, size - 24);
|
||||
} else
|
||||
io_->seek(cur_pos + size, BasicIo::beg);
|
||||
|
||||
localPosition_ = io_->tell();
|
||||
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_->read(buf.data(), 2);
|
||||
streamNumber_ = Exiv2::getUShort(buf.data(), littleEndian);
|
||||
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
|
||||
|
||||
io_->read(buf.data(), 2);
|
||||
io_->read(buf.data(), BUFF_MIN_SIZE);
|
||||
avgTimePerFrame = Util::getUint64_t(buf);
|
||||
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_);
|
||||
|
||||
if (previousStream < streamNumber_ && avgTimePerFrame != 0)
|
||||
xmpData()["Xmp.video.FrameRate"] = 10000000. / avgTimePerFrame;
|
||||
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
|
||||
}
|
||||
|
||||
previousStream = streamNumber_;
|
||||
io_->seek(cur_pos + size, BasicIo::beg);
|
||||
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
|
||||
|
||||
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
|
||||
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() {
|
||||
DataBuf buf(20);
|
||||
byte guidBuf[GUI_SIZE];
|
||||
int stream = 0;
|
||||
DataBuf streamTypedBuf = io_->read(GUID);
|
||||
|
||||
auto stream_type = getGUID(streamTypedBuf);
|
||||
|
||||
enum streamTypeInfo { Audio = 1, Video = 2 };
|
||||
io_->read(guidBuf, GUI_SIZE);
|
||||
char streamType[GUID_SIZE] = "";
|
||||
int stream = 0;
|
||||
|
||||
getGUID(guidBuf, streamType);
|
||||
auto tv = Exiv2::find(GUIDReferenceTags, streamType);
|
||||
io_->read(guidBuf, GUI_SIZE);
|
||||
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 (tag_stream_type->second == "Video_Media")
|
||||
stream = Video;
|
||||
|
||||
if (compareTag(exvGettext(tv->label_), "Audio_Media"))
|
||||
stream = Audio;
|
||||
else if (compareTag(exvGettext(tv->label_), "Video_Media"))
|
||||
stream = Video;
|
||||
io_->seek(io_->tell() + GUID, BasicIo::beg); // ignore Error Correction Type
|
||||
|
||||
io_->read(buf.data(), BUFF_MIN_SIZE);
|
||||
if (stream == Video)
|
||||
xmpData()["Xmp.video.TimeOffset"] = Util::getUint64_t(buf);
|
||||
else if (stream == Audio)
|
||||
xmpData()["Xmp.audio.TimeOffset"] = Util::getUint64_t(buf);
|
||||
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;
|
||||
|
||||
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;
|
||||
auto specific_data_length = readDWORDTag(io_);
|
||||
auto correction_data_length = readDWORDTag(io_);
|
||||
|
||||
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"]
|
||||
io_->seek(io_->tell() + WORD /*Flags*/ + DWORD /*Reserved*/ + specific_data_length + correction_data_length,
|
||||
BasicIo::beg);
|
||||
}
|
||||
|
||||
io_->read(buf.data(), 2);
|
||||
temp = Exiv2::getUShort(buf.data(), littleEndian);
|
||||
if (stream == Audio)
|
||||
xmpData()["Xmp.audio.ChannelType"] = temp;
|
||||
|
||||
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;
|
||||
}
|
||||
} // 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;
|
||||
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";
|
||||
|
||||
while (codecCount--) {
|
||||
std::memset(buf.data(), 0x0, buf.size());
|
||||
io_->read(buf.data(), 2);
|
||||
codecType = Exiv2::getUShort(buf.data(), littleEndian);
|
||||
uint16_t codec_name_length = readWORDTag(io_) * 2;
|
||||
if (codec_name_length)
|
||||
xmpData()[codec + std::string(".CodecName")] = readStringWcharTag(io_, codec_name_length);
|
||||
|
||||
io_->read(buf.data(), 2);
|
||||
descLength = Exiv2::getUShort(buf.data(), littleEndian) * 2;
|
||||
uint16_t codec_desc_length = readWORDTag(io_);
|
||||
if (codec_desc_length)
|
||||
xmpData()[codec + std::string(".CodecDescription")] = readStringWcharTag(io_, codec_desc_length);
|
||||
|
||||
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);
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
while (localPosition_ < cur_pos + size)
|
||||
decodeBlock();
|
||||
|
||||
io_->seek(cur_pos + size, BasicIo::beg);
|
||||
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::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] = "";
|
||||
void AsfVideo::extendedContentDescription() {
|
||||
uint16_t content_descriptor_count = readWORDTag(io_);
|
||||
std::string value;
|
||||
|
||||
while (recordCount--) {
|
||||
std::memset(buf.data(), 0x0, buf.size());
|
||||
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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
v->read(Util::toString16(buf));
|
||||
|
||||
io_->read(buf.data(), 2);
|
||||
dataType = Exiv2::getUShort(buf.data(), littleEndian);
|
||||
|
||||
io_->read(buf.data(), 2);
|
||||
dataLength = Exiv2::getUShort(buf.data(), littleEndian);
|
||||
|
||||
// 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 (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()));
|
||||
}
|
||||
value += std::string(", ");
|
||||
}
|
||||
|
||||
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
|
||||
xmpData()["Xmp.video.ExtendedContentDescription"] = value;
|
||||
} // AsfVideo::extendedContentDescription
|
||||
|
||||
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_);
|
||||
|
||||
if (title_length)
|
||||
xmpData()["Xmp.video.Title"] = readStringWcharTag(io_, title_length);
|
||||
|
||||
if (author_length)
|
||||
xmpData()["Xmp.video.Author"] = readStringWcharTag(io_, author_length);
|
||||
|
||||
if (copyright_length)
|
||||
xmpData()["Xmp.video.Copyright"] = readStringWcharTag(io_, copyright_length);
|
||||
|
||||
if (desc_length)
|
||||
xmpData()["Xmp.video.Description"] = readStringWcharTag(io_, desc_length);
|
||||
|
||||
if (rating_length)
|
||||
xmpData()["Xmp.video.Rating"] = readStringWcharTag(io_, rating_length);
|
||||
|
||||
} // AsfVideo::extendedContentDescription
|
||||
|
||||
void AsfVideo::fileProperties() {
|
||||
DataBuf buf(BUFF_MIN_SIZE);
|
||||
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_);
|
||||
|
||||
byte guidBuf[GUI_SIZE];
|
||||
io_->read(guidBuf, GUI_SIZE);
|
||||
char fileID[GUID_SIZE] = "";
|
||||
int count = 7;
|
||||
getGUID(guidBuf, fileID);
|
||||
xmpData()["Xmp.video.FileID"] = fileID;
|
||||
|
||||
const TagDetails* td;
|
||||
|
||||
while (count--) {
|
||||
td = Exiv2::find(filePropertiesTags, (count + 1));
|
||||
io_->read(buf.data(), BUFF_MIN_SIZE);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 getUint64_t(Exiv2::DataBuf& buf) {
|
||||
uint64_t temp = 0;
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
temp = temp + static_cast<uint64_t>(buf.data()[i] * (pow(static_cast<float>(256), i)));
|
||||
}
|
||||
return temp;
|
||||
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);
|
||||
}
|
||||
} // namespace Util
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//! 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, size_t length);
|
||||
|
||||
[[nodiscard]] std::string readStringTag(Exiv2::BasicIo::UniquePtr& io, size_t length = DWORD);
|
||||
|
||||
} // 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();
|
||||
|
||||
|
||||
1320
src/riffvideo.cpp
1320
src/riffvideo.cpp
File diff suppressed because it is too large
Load Diff
BIN
test/data/Free_Test_Data_500KB_WAV.wav
Normal file
BIN
test/data/Free_Test_Data_500KB_WAV.wav
Normal file
Binary file not shown.
BIN
test/data/flame.avi
Normal file
BIN
test/data/flame.avi
Normal file
Binary file not shown.
BIN
test/data/sample_640x360.mov
Normal file
BIN
test/data/sample_640x360.mov
Normal file
Binary file not shown.
BIN
test/data/sample_960x540.asf
Normal file
BIN
test/data/sample_960x540.asf
Normal file
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
|
||||
26
test/data/test_reference_files/flame.avi.out
Normal file
26
test/data/test_reference_files/flame.avi.out
Normal file
@ -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
|
||||
50
test/data/test_reference_files/sample_640x360.mov.out
Normal file
50
test/data/test_reference_files/sample_640x360.mov.out
Normal file
@ -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
|
||||
15
test/data/test_reference_files/sample_960x540.asf.out
Normal file
15
test/data/test_reference_files/sample_960x540.asf.out
Normal file
@ -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…
Reference in New Issue
Block a user