This source file includes following definitions.
- mCurrentStreamByte
- luminanceParamFromJson
- percentagesFromJson
- percentagesFromJson
- bezierCurveFromJson
- appendBits
- setPayloadSize
- shiftData
- frameMetadataFromJson
- movieMetadataFromJson
- extendedInfoFrameMetadataFromJson
- movieExtendedInfoFrameMetadataFromJson
- fillMetadataArray
- clear
#include "metadataFromJson.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include "sstream"
#include "sys/stat.h"
#include "BasicStructures.h"
#include "SeiMetadataDictionary.h"
#define M_PI 3.14159265358979323846
using namespace SeiMetadataDictionary;
class metadataFromJson::DynamicMetaIO
{
public:
DynamicMetaIO() :
mCurrentStreamBit(8),
mCurrentStreamByte(0)
{}
~DynamicMetaIO(){}
int mCurrentStreamBit;
int mCurrentStreamByte;
bool luminanceParamFromJson(const Json &data, LuminanceParameters &obj)
{
JsonObject lumJsonData = data.object_items();
if(!lumJsonData.empty())
{
JsonObject percentileData = lumJsonData[PercentileNames::TagName].object_items();
obj.order = percentileData[PercentileNames::NumberOfPercentiles].int_value();
obj.averageLuminance = static_cast<float>(lumJsonData[LuminanceNames::AverageRGB].number_value());
obj.maxRLuminance = static_cast<float>(lumJsonData[LuminanceNames::MaxSCL0].number_value());
obj.maxGLuminance = static_cast<float>(lumJsonData[LuminanceNames::MaxSCL1].number_value());
obj.maxBLuminance = static_cast<float>(lumJsonData[LuminanceNames::MaxSCL2].number_value());
if(!percentileData.empty())
{
obj.percentiles.resize(obj.order);
for(int i = 0; i < obj.order; ++i)
{
std::string percentileTag = PercentileNames::TagName;
percentileTag += std::to_string(i);
obj.percentiles[i] = static_cast<unsigned int>(percentileData[percentileTag].int_value());
}
}
return true;
}
return false;
}
bool percentagesFromJson(const Json &data, std::vector<unsigned int> &percentages)
{
JsonObject jsonData = data.object_items();
if(!jsonData.empty())
{
JsonObject percentileData = jsonData[PercentileNames::TagName].object_items();
int order = percentileData[PercentileNames::NumberOfPercentiles].int_value();
percentages.resize(order);
for(int i = 0; i < order; ++i)
{
std::string percentileTag = PercentileNames::PercentilePercentageValue[i];
percentages[i] = static_cast<unsigned int>(percentileData[percentileTag].int_value());
}
return true;
}
return false;
}
bool percentagesFromJson(const Json &data, unsigned int *percentages)
{
JsonObject jsonData = data.object_items();
if(!jsonData.empty())
{
JsonObject percentileData = jsonData[PercentileNames::TagName].object_items();
int order = percentileData[PercentileNames::NumberOfPercentiles].int_value();
for(int i = 0; i < order; ++i)
{
std::string percentileTag = PercentileNames::PercentilePercentageValue[i];
percentages[i] = static_cast<unsigned int>(percentileData[percentileTag].int_value());
}
return true;
}
return false;
}
bool bezierCurveFromJson(const Json &data, BezierCurveData &obj)
{
JsonObject jsonData = data.object_items();
if(!jsonData.empty())
{
obj.order = jsonData[BezierCurveNames::NumberOfAnchors].int_value();
obj.coeff.resize(obj.order);
obj.sPx = jsonData[BezierCurveNames::KneePointX].int_value();
obj.sPy = jsonData[BezierCurveNames::KneePointY].int_value();
for(int i = 0; i < obj.order; ++i)
{
obj.coeff[i] = jsonData[BezierCurveNames::Anchors[i]].int_value();
}
return true;
}
return false;
}
template<typename T>
void appendBits(uint8_t *dataStream, T data, int bitsToWrite)
{
while (bitsToWrite > 0)
{
if (bitsToWrite < mCurrentStreamBit )
{
int bitshift = mCurrentStreamBit - bitsToWrite;
dataStream[mCurrentStreamByte] += static_cast<uint8_t>(data << bitshift);
mCurrentStreamBit -= bitsToWrite;
bitsToWrite = 0;
}
else
{
int bitshift = bitsToWrite - mCurrentStreamBit;
dataStream[mCurrentStreamByte] += static_cast<uint8_t>(data >> bitshift);
bitsToWrite -= mCurrentStreamBit ;
mCurrentStreamBit = 8;
mCurrentStreamByte++;
}
}
}
void setPayloadSize(uint8_t *dataStream, int positionOnStream, int payload)
{
int payloadBytes = 1;
for(;payload >= 0xFF; payload -= 0xFF, ++payloadBytes);
if(payloadBytes > 1)
{
shiftData(dataStream, payloadBytes-1, mCurrentStreamByte, positionOnStream);
mCurrentStreamByte += payloadBytes-1;
for(int i = 0; i < payloadBytes; ++i)
{
if(payloadBytes-1 == i)
{
dataStream[positionOnStream++] = static_cast<uint8_t>(payload);
}
else
{
dataStream[positionOnStream++] = 0xFF;
}
}
}
else
{
dataStream[positionOnStream] = static_cast<uint8_t>(payload);
}
}
void shiftData(uint8_t *dataStream, int shiftSize, int streamSize, int startPoint = 0)
{
for(int i = streamSize; i > startPoint; --i)
{
dataStream[i + shiftSize] = dataStream[i];
}
}
};
metadataFromJson::metadataFromJson() :
mPimpl(new DynamicMetaIO())
{
}
metadataFromJson::~metadataFromJson()
{
delete mPimpl;
}
bool metadataFromJson::frameMetadataFromJson(const char* filePath,
int frame,
uint8_t *&metadata)
{
std::string path(filePath);
JsonArray fileData = JsonHelper::readJsonArray(path);
if(fileData.empty())
{
return false;
}
int numFrames = static_cast<int>(fileData.size());
if(frame >= numFrames)
{
return false;
}
int mSEIBytesToRead = 509;
if(metadata)
{
delete(metadata);
}
metadata = new uint8_t[mSEIBytesToRead];
mPimpl->mCurrentStreamBit = 8;
mPimpl->mCurrentStreamByte = 1;
for(int j = 0; j < mSEIBytesToRead; ++j)
{
(metadata)[j] = 0;
}
fillMetadataArray(fileData, frame, metadata);
mPimpl->setPayloadSize(metadata, 0, mPimpl->mCurrentStreamByte);
return true;
}
int metadataFromJson::movieMetadataFromJson(const char* filePath, uint8_t **&metadata)
{
std::string path(filePath);
JsonArray fileData = JsonHelper::readJsonArray(path);
if (fileData.empty())
{
return -1;
}
int numFrames = static_cast<int>(fileData.size());
metadata = new uint8_t*[numFrames];
for (int frame = 0; frame < numFrames; ++frame)
{
metadata[frame] = new uint8_t[509];
for (int i = 0; i < 509; ++i)
{
metadata[frame][i] = 0;
}
mPimpl->mCurrentStreamBit = 8;
mPimpl->mCurrentStreamByte = 1;
fillMetadataArray(fileData, frame, metadata[frame]);
mPimpl->setPayloadSize(metadata[frame], 0, mPimpl->mCurrentStreamByte);
}
return numFrames;
}
bool metadataFromJson::extendedInfoFrameMetadataFromJson(const char* filePath,
int frame,
uint8_t *&metadata)
{
std::string path(filePath);
JsonArray fileData = JsonHelper::readJsonArray(path);
if (fileData.empty())
{
return false;
}
int numFrames = static_cast<int>(fileData.size());
if (frame >= numFrames)
{
return false;
}
int mSEIBytesToRead = 509;
if (metadata)
{
delete(metadata);
}
metadata = new uint8_t[mSEIBytesToRead];
mPimpl->mCurrentStreamBit = 8;
mPimpl->mCurrentStreamByte = 0;
for (int j = 0; j < mSEIBytesToRead; ++j)
{
(metadata)[j] = 0;
}
const uint16_t extendedInfoframeType = 0x0004;
mPimpl->appendBits(metadata, extendedInfoframeType, 16);
mPimpl->mCurrentStreamByte += 2;
fillMetadataArray(fileData, frame, metadata);
metadata[2] = (mPimpl->mCurrentStreamByte & 0xFF00) >> 8;
metadata[3] = (mPimpl->mCurrentStreamByte & 0x00FF);
return true;
}
int metadataFromJson::movieExtendedInfoFrameMetadataFromJson(const char* filePath, uint8_t **&metadata)
{
std::string path(filePath);
JsonArray fileData = JsonHelper::readJsonArray(path);
if(fileData.empty())
{
return -1;
}
int numFrames = static_cast<int>(fileData.size());
metadata = new uint8_t*[numFrames];
for(int frame = 0; frame < numFrames; ++frame)
{
metadata[frame] = new uint8_t[509];
for(int i = 0; i < 509; ++i)
{
metadata[frame][i] = 0;
}
mPimpl->mCurrentStreamBit = 8;
mPimpl->mCurrentStreamByte = 0;
const uint16_t extendedInfoframeType = 0x0004;
mPimpl->appendBits(metadata[frame], extendedInfoframeType, 16);
mPimpl->mCurrentStreamByte += 2;
fillMetadataArray(fileData, frame, metadata[frame]);
metadata[frame][2] = (mPimpl->mCurrentStreamByte & 0xFF00) >> 8;
metadata[frame][3] = (mPimpl->mCurrentStreamByte & 0x00FF);
}
return numFrames;
}
void metadataFromJson::fillMetadataArray(const JsonArray &fileData, int frame, uint8_t *&metadata)
{
const uint8_t countryCode = 0xB5;
const uint16_t terminalProviderCode = 0x003C;
const uint16_t terminalProviderOrientedCode = 0x0001;
const uint8_t applicationIdentifier = 4;
const uint8_t applicationVersion = 0;
mPimpl->appendBits(metadata, countryCode, 8);
mPimpl->appendBits(metadata, terminalProviderCode, 16);
mPimpl->appendBits(metadata, terminalProviderOrientedCode, 16);
mPimpl->appendBits(metadata, applicationIdentifier, 8);
mPimpl->appendBits(metadata, applicationVersion, 8);
JsonArray jsonArray = fileData[frame][JsonDataKeys::LocalParameters].array_items();
int ellipsesNum = static_cast<int>(jsonArray.size() > 2 ? 2 : jsonArray.size());
uint16_t numWindows = 1 + static_cast<uint16_t>(ellipsesNum);
mPimpl->appendBits(metadata, numWindows, 2);
for (int i = 0; i < ellipsesNum; ++i)
{
mPimpl->appendBits(metadata, jsonArray[i][EllipseSelectionNames::WindowData]
[EllipseSelectionNames::WindowUpperLeftCornerX].int_value(), 16);
mPimpl->appendBits(metadata, jsonArray[i][EllipseSelectionNames::WindowData]
[EllipseSelectionNames::WindowUpperLeftCornerY].int_value(), 16);
mPimpl->appendBits(metadata, jsonArray[i][EllipseSelectionNames::WindowData]
[EllipseSelectionNames::WindowLowerRightCornerX].int_value(), 16);
mPimpl->appendBits(metadata, jsonArray[i][EllipseSelectionNames::WindowData]
[EllipseSelectionNames::WindowLowerRightCornerY].int_value(), 16);
JsonObject ellipseJsonObject = jsonArray[i][EllipseNames::TagName].object_items();
mPimpl->appendBits(metadata,
static_cast<uint16_t>(ellipseJsonObject[EllipseNames::CenterOfEllipseX].int_value()),
16);
mPimpl->appendBits(metadata,
static_cast<uint16_t>(ellipseJsonObject[EllipseNames::CenterOfEllipseY].int_value()),
16);
int angle = ellipseJsonObject[EllipseNames::RotationAngle].int_value();
uint8_t rotationAngle = static_cast<uint8_t>((angle > 180.0) ? angle - 180.0 : angle);
mPimpl->appendBits(metadata, rotationAngle, 8);
uint16_t semimajorExternalAxis =
static_cast<uint16_t>(ellipseJsonObject[EllipseNames::SemiMajorAxisExternalEllipse].int_value());
uint16_t semiminorExternalAxis =
static_cast<uint16_t>(ellipseJsonObject[EllipseNames::SemiMinorAxisExternalEllipse].int_value());
uint16_t semimajorInternalEllipse =
static_cast<uint16_t>(ellipseJsonObject[EllipseNames::SemiMajorAxisInternalEllipse].int_value());
mPimpl->appendBits(metadata, semimajorInternalEllipse, 16);
mPimpl->appendBits(metadata, semimajorExternalAxis, 16);
mPimpl->appendBits(metadata, semiminorExternalAxis, 16);
uint8_t overlapProcessOption = static_cast<uint8_t>(ellipseJsonObject[EllipseNames::OverlapProcessOption].int_value());
mPimpl->appendBits(metadata, overlapProcessOption, 1);
}
uint32_t TEMPmonitorPeak = fileData[frame][JsonDataKeys::TargetDisplayLuminance].int_value();
mPimpl->appendBits(metadata, TEMPmonitorPeak, 27);
uint8_t targetedSystemDisplayActualPeakLuminanceFlag = 0;
mPimpl->appendBits(metadata, targetedSystemDisplayActualPeakLuminanceFlag, 1);
if (targetedSystemDisplayActualPeakLuminanceFlag)
{
}
for (int w = 0; w < numWindows; ++w)
{
Json lumObj = fileData[frame][LuminanceNames::TagName];
LuminanceParameters luminanceData;
if (!mPimpl->luminanceParamFromJson(lumObj, luminanceData))
{
std::cout << "error parsing luminance parameters frame: " << w << std::endl;
}
mPimpl->appendBits(metadata, static_cast<uint8_t>(((int)luminanceData.maxRLuminance & 0x10000) >> 16), 1);
mPimpl->appendBits(metadata, static_cast<uint16_t>((int)luminanceData.maxRLuminance & 0xFFFF), 16);
mPimpl->appendBits(metadata, static_cast<uint8_t>(((int)luminanceData.maxGLuminance & 0x10000) >> 16), 1);
mPimpl->appendBits(metadata, static_cast<uint16_t>((int)luminanceData.maxGLuminance & 0xFFFF), 16);
mPimpl->appendBits(metadata, static_cast<uint8_t>(((int)luminanceData.maxBLuminance & 0x10000) >> 16), 1);
mPimpl->appendBits(metadata, static_cast<uint16_t>((int)luminanceData.maxBLuminance & 0xFFFF), 16);
mPimpl->appendBits(metadata, static_cast<uint8_t>(((int)luminanceData.averageLuminance & 0x10000) >> 16), 1);
mPimpl->appendBits(metadata, static_cast<uint16_t>((int)luminanceData.averageLuminance & 0xFFFF), 16);
uint8_t numDistributionMaxrgbPercentiles = static_cast<uint8_t>(luminanceData.order);
mPimpl->appendBits(metadata, numDistributionMaxrgbPercentiles, 4);
std::vector<unsigned int>percentilPercentages;
mPimpl->percentagesFromJson(lumObj, percentilPercentages);
for (int i = 0; i < numDistributionMaxrgbPercentiles; ++i)
{
uint8_t distributionMaxrgbPercentage = static_cast<uint8_t>(percentilPercentages.at(i));
mPimpl->appendBits(metadata, distributionMaxrgbPercentage, 7);
unsigned int ithPercentile = luminanceData.percentiles.at(i);
uint8_t highValue = static_cast<uint8_t>((ithPercentile & 0x10000) >> 16);
uint16_t lowValue = static_cast<uint16_t>(ithPercentile & 0xFFFF);
mPimpl->appendBits(metadata, highValue, 1);
mPimpl->appendBits(metadata, lowValue, 16);
}
uint16_t fractionBrightPixels = 1;
mPimpl->appendBits(metadata, fractionBrightPixels, 10);
}
uint8_t masteringDisplayActualPeakLuminanceFlag = 0;
mPimpl->appendBits(metadata, masteringDisplayActualPeakLuminanceFlag, 1);
if (masteringDisplayActualPeakLuminanceFlag)
{
}
for (int w = 0; w < numWindows; ++w)
{
uint8_t toneMappingFlag = 1;
mPimpl->appendBits(metadata, toneMappingFlag, 1);
if (toneMappingFlag)
{
Json bezierData = fileData[frame][BezierCurveNames::TagName];
BezierCurveData curveData;
if (w == 0)
{
if (!mPimpl->bezierCurveFromJson(bezierData, curveData))
{
std::cout << "error parsing bezierCurve frame: " << w << std::endl;
}
}
else
{
if (!mPimpl->bezierCurveFromJson(jsonArray[w - 1][BezierCurveNames::TagName], curveData))
{
std::cout << "error parsing bezierCurve ellipse: " << w - 1 << std::endl;
}
}
uint16_t kneePointX = static_cast<uint16_t>(curveData.sPx);
mPimpl->appendBits(metadata, kneePointX, 12);
uint16_t kneePointY = static_cast<uint16_t>(curveData.sPy);
mPimpl->appendBits(metadata, kneePointY, 12);
uint8_t numBezierCurveAnchors = static_cast<uint8_t>(curveData.order);
mPimpl->appendBits(metadata, numBezierCurveAnchors, 4);
for (int i = 0; i < numBezierCurveAnchors; ++i)
{
uint16_t anchor = static_cast<uint16_t>(curveData.coeff.at(i));
mPimpl->appendBits(metadata, anchor, 10);
}
}
}
bool colorSaturationMappingFlag = 0;
mPimpl->appendBits(metadata, colorSaturationMappingFlag, 1);
if (colorSaturationMappingFlag)
{
}
if (mPimpl->mCurrentStreamBit == 8)
{
mPimpl->mCurrentStreamByte -= 1;
}
}
void metadataFromJson::clear(uint8_t **&metadata, const int numberOfFrames)
{
if (metadata && numberOfFrames > 0)
{
for (int i = 0; i < numberOfFrames; ++i)
{
if (metadata[i])
{
delete[] metadata[i];
}
}
delete[] metadata;
metadata = NULL;
}
}