Skip to content

Commit

Permalink
rework of aspectRatio calculation for all video formats and rework th…
Browse files Browse the repository at this point in the history
…e decoding of asf tags
  • Loading branch information
mohamedchebbii authored and neheb committed Feb 11, 2023
1 parent 4bdee6f commit bed8d3d
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 360 deletions.
46 changes: 39 additions & 7 deletions include/exiv2/asfvideo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class EXIV2API AsfVideo : public Image {
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
*/
*/

explicit AsfVideo(BasicIo::UniquePtr io);
//@}

Expand All @@ -47,6 +48,41 @@ class EXIV2API AsfVideo : public Image {
//@{
[[nodiscard]] std::string mimeType() const override;
//@}

/* @class GUID_struct
*
* @brief A class to represent a globally unique identifier (GUID) structure
*
* This class represents a globally unique identifier (GUID) structure which is used to identify objects in a
* distributed environment. A GUID is a unique identifier that is generated on a computer and can be used to
* identify an object across different systems. The GUID structure is comprised of four 32-bit values and an
* array of 8 bytes.
*
* @note The byte order of the GUID structure is in little endian.
*
* @see https://en.wikipedia.org/wiki/Globally_unique_identifier
*
*/
class GUIDTag {
uint32_t data1_;
uint16_t data2_;
uint16_t data3_;
std::array<byte, 8> data4_;

public:
bool operator==(const GUIDTag& other) const;

// Constructor to create a GUID object by passing individual values for each attribute
GUIDTag(unsigned int data1, unsigned short data2, unsigned short data3, std::array<byte, 8> data4);

// Constructor to create a GUID object from a byte array
GUIDTag(const uint8_t* bytes);

std::string to_string();

bool operator<(const GUIDTag& other) const;
};

private:
static constexpr size_t CODEC_TYPE_VIDEO = 1;
static constexpr size_t CODEC_TYPE_AUDIO = 2;
Expand Down Expand Up @@ -78,6 +114,8 @@ class EXIV2API AsfVideo : public Image {
position. Calls tagDecoder() or skips to next tag, if required.
*/
void decodeBlock();

void decodeHeader();
/*!
@brief Interpret File_Properties tag information, and save it in
the respective XMP container.
Expand Down Expand Up @@ -118,12 +156,6 @@ class EXIV2API AsfVideo : public Image {

void DegradableJPEGMedia();

/*!
@brief Calculates Aspect Ratio of a video, and stores it in the
respective XMP container.
*/
void aspectRatio();

private:
//! Variable to store height and width of a video frame.
uint64_t height_, width_;
Expand Down
5 changes: 0 additions & 5 deletions include/exiv2/matroskavideo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,6 @@ class EXIV2API MatroskaVideo : public Image {
void decodeBooleanTags(const Internal::MatroskaTag* tag, const byte* buf, size_t size);
void decodeDateTags(const Internal::MatroskaTag* tag, const byte* buf, size_t size);
void decodeFloatTags(const Internal::MatroskaTag* tag, const byte* buf, size_t size);
/*!Internal::
@brief Calculates Aspect Ratio of a video, and stores it in the
respective XMP container.
*/
void aspectRatio();

private:
//! Variable to check the end of metadata traversing.
Expand Down
5 changes: 0 additions & 5 deletions include/exiv2/quicktimevideo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,6 @@ class EXIV2API QuickTimeVideo : public Image {
@param size Size of the data block that is to skipped.
*/
void discard(size_t size);
/*!
@brief Calculates Aspect Ratio of a video, and stores it in the
respective XMP container.
*/
void aspectRatio();

//! Variable which stores Time Scale unit, used to calculate time.
uint64_t timeScale_ = 0;
Expand Down
416 changes: 200 additions & 216 deletions src/asfvideo.cpp

Large diffs are not rendered by default.

15 changes: 10 additions & 5 deletions src/helper_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <codecvt>
#include <cstring>
#include <locale>
#include <numeric>
#include "enforce.hpp"

std::string string_from_unterminated(const char* data, size_t data_length) {
Expand All @@ -17,11 +18,6 @@ std::string string_from_unterminated(const char* data, size_t data_length) {
}

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 utf16ToUtf8(const std::wstring& wstr) {
using convert_typeX = std::codecvt_utf8<wchar_t>;
Expand Down Expand Up @@ -65,4 +61,13 @@ std::string readStringTag(BasicIo::UniquePtr& io, size_t length) {
return Exiv2::toString(FieldBuf.data()).substr(0, length);
}

std::string getAspectRatio(size_t width, size_t height) {
if (height == 0 || width == 0)
return std::to_string(width) + ":" + std::to_string(height);

int ratioWidth = width / std::gcd(width, height);
int ratioHeight = height / std::gcd(width, height);
return std::to_string(ratioWidth) + ":" + std::to_string(ratioHeight);
}

} // namespace Exiv2
12 changes: 5 additions & 7 deletions src/helper_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@
std::string string_from_unterminated(const char* data, size_t data_length);

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);

static constexpr size_t BYTE = 0x1;
static constexpr size_t WCHAR = 0x2;
Expand Down Expand Up @@ -60,5 +53,10 @@ std::string utf16ToUtf8(const std::wstring& wstr);

[[nodiscard]] std::string readStringTag(Exiv2::BasicIo::UniquePtr& io, size_t length = DWORD);

/*!
@brief Calculates Aspect Ratio of a video
*/
[[nodiscard]] std::string getAspectRatio(size_t width, size_t height);

} // namespace Exiv2
#endif // HELPER_FUNCTIONS_HPP
38 changes: 2 additions & 36 deletions src/matroskavideo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "basicio.hpp"
#include "error.hpp"
#include "futils.hpp"
#include "helper_functions.hpp"
#include "matroskavideo.hpp"
#include "tags.hpp"
#include "tags_int.hpp"
Expand Down Expand Up @@ -606,7 +607,7 @@ void MatroskaVideo::readMetadata() {
while (continueTraversing_)
decodeBlock();

aspectRatio();
xmpData_["Xmp.video.AspectRatio"] = getAspectRatio(width_, height_);
}

void MatroskaVideo::decodeBlock() {
Expand Down Expand Up @@ -888,41 +889,6 @@ void MatroskaVideo::decodeFloatTags(const MatroskaTag* tag, const byte* buf, siz
}
}

void MatroskaVideo::aspectRatio() {
double aspectRatio = static_cast<double>(width_) / static_cast<double>(height_);
aspectRatio = floor(aspectRatio * 10) / 10;
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;

auto aR = static_cast<int>((aspectRatio * 10.0) + 0.1);

switch (aR) {
case 13:
xmpData_["Xmp.video.AspectRatio"] = "4:3";
break;
case 17:
xmpData_["Xmp.video.AspectRatio"] = "16:9";
break;
case 10:
xmpData_["Xmp.video.AspectRatio"] = "1:1";
break;
case 16:
xmpData_["Xmp.video.AspectRatio"] = "16:10";
break;
case 22:
xmpData_["Xmp.video.AspectRatio"] = "2.21:1";
break;
case 23:
xmpData_["Xmp.video.AspectRatio"] = "2.35:1";
break;
case 12:
xmpData_["Xmp.video.AspectRatio"] = "5:4";
break;
default:
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;
break;
}
}

uint32_t MatroskaVideo::findBlockSize(byte b) {
if (b & 128)
return 1;
Expand Down
40 changes: 2 additions & 38 deletions src/quicktimevideo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "enforce.hpp"
#include "error.hpp"
#include "futils.hpp"
#include "helper_functions.hpp"
#include "quicktimevideo.hpp"
#include "safe_op.hpp"
#include "tags.hpp"
Expand Down Expand Up @@ -528,7 +529,7 @@ void QuickTimeVideo::readMetadata() {
while (continueTraversing_)
decodeBlock();

aspectRatio();
xmpData_["Xmp.video.AspectRatio"] = getAspectRatio(width_, height_);
} // QuickTimeVideo::readMetadata

void QuickTimeVideo::decodeBlock(std::string const& entered_from) {
Expand Down Expand Up @@ -1536,43 +1537,6 @@ void QuickTimeVideo::movieHeaderDecoder(size_t size) {
io_->readOrThrow(buf.data(), size % 4);
} // QuickTimeVideo::movieHeaderDecoder

void QuickTimeVideo::aspectRatio() {
// TODO - Make a better unified method to handle all cases of Aspect Ratio

double aspectRatio = static_cast<double>(width_) / static_cast<double>(height_);
aspectRatio = floor(aspectRatio * 10) / 10;
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;

auto aR = static_cast<int>((aspectRatio * 10.0) + 0.1);

switch (aR) {
case 13:
xmpData_["Xmp.video.AspectRatio"] = "4:3";
break;
case 17:
xmpData_["Xmp.video.AspectRatio"] = "16:9";
break;
case 10:
xmpData_["Xmp.video.AspectRatio"] = "1:1";
break;
case 16:
xmpData_["Xmp.video.AspectRatio"] = "16:10";
break;
case 22:
xmpData_["Xmp.video.AspectRatio"] = "2.21:1";
break;
case 23:
xmpData_["Xmp.video.AspectRatio"] = "2.35:1";
break;
case 12:
xmpData_["Xmp.video.AspectRatio"] = "5:4";
break;
default:
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;
break;
}
} // QuickTimeVideo::aspectRatio

Image::UniquePtr newQTimeInstance(BasicIo::UniquePtr io, bool /*create*/) {
auto image = std::make_unique<QuickTimeVideo>(std::move(io));
if (!image->good()) {
Expand Down
41 changes: 2 additions & 39 deletions src/riffvideo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,8 @@ void RiffVideo::readAviHeader() {
io_->seekOrThrow(io_->tell() + DWORD * 4, BasicIo::beg,
ErrorCode::kerFailedToReadImageData); // TimeScale, DataRate, StartTime, DataLength

fillAspectRatio(width, height);
xmpData_["Xmp.video.AspectRatio"] = getAspectRatio(width, height);

fillDuration(frame_rate, frame_count);
}

Expand Down Expand Up @@ -758,44 +759,6 @@ void RiffVideo::fillDuration(double frame_rate, size_t frame_count) {
xmpData_["Xmp.video.Duration"] = duration; // Duration in number of seconds
} // RiffVideo::fillDuration

void RiffVideo::fillAspectRatio(size_t width, size_t height) {
if (height == 0)
return;
double aspectRatio = static_cast<double>(width) / height;
aspectRatio = floor(aspectRatio * 10) / 10;
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;

auto aR = static_cast<int>((aspectRatio * 10.0) + 0.1);

switch (aR) {
case 13:
xmpData_["Xmp.video.AspectRatio"] = "4:3";
break;
case 17:
xmpData_["Xmp.video.AspectRatio"] = "16:9";
break;
case 10:
xmpData_["Xmp.video.AspectRatio"] = "1:1";
break;
case 16:
xmpData_["Xmp.video.AspectRatio"] = "16:10";
break;
case 22:
xmpData_["Xmp.video.AspectRatio"] = "2.21:1";
break;
case 23:
xmpData_["Xmp.video.AspectRatio"] = "2.35:1";
break;
case 12:
xmpData_["Xmp.video.AspectRatio"] = "5:4";
break;
default:
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;

break;
}
}

Image::UniquePtr newRiffInstance(BasicIo::UniquePtr io, bool /*create*/) {
auto image = std::make_unique<RiffVideo>(std::move(io));
if (!image->good()) {
Expand Down
2 changes: 1 addition & 1 deletion test/data/test_reference_files/flame.avi.out
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ 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.AspectRatio XmpText 5 16:15 16:15
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
Expand Down
2 changes: 1 addition & 1 deletion test/data/test_reference_files/small_video.mp4.out
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ Xmp.audio.ChannelType XmpText 1 2 2
Xmp.audio.BitsPerSample XmpText 2 16 16
Xmp.audio.SampleRate XmpText 5 44100 44100
Xmp.audio.HandlerVendorID XmpText 5 Apple Apple
Xmp.video.AspectRatio XmpText 3 0.5 0.5
Xmp.video.AspectRatio XmpText 4 9:16 9:16

0 comments on commit bed8d3d

Please sign in to comment.