Skip to content

Commit

Permalink
Add P010 HDR10 video format support
Browse files Browse the repository at this point in the history
  • Loading branch information
awawa-dev committed Oct 31, 2024
1 parent 85d321e commit b04b49b
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 49 deletions.
2 changes: 2 additions & 0 deletions include/lut-calibrator/BestResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ struct BestResult
double upYLimit = 0;
double downYLimit = 0;
double yShift = 0;
bool isSourceP010 = false;
} signal;

long long int minError = MAX_CALIBRATION_ERROR;
Expand Down Expand Up @@ -121,6 +122,7 @@ struct BestResult
out << "bestResult.signal.upYLimit = " << std::to_string(signal.upYLimit) << ";" << std::endl;
out << "bestResult.signal.downYLimit = " << std::to_string(signal.downYLimit) << ";" << std::endl;
out << "bestResult.signal.yShift = " << std::to_string(signal.yShift) << ";" << std::endl;
out << "bestResult.signal.isSourceP010 = " << std::to_string(signal.isSourceP010) << ";" << std::endl;
out << "bestResult.minError = " << std::to_string(std::round(minError * 100.0) / 30000.0) << ";" << std::endl;
out << "*/" << std::endl;
}
Expand Down
4 changes: 3 additions & 1 deletion include/lut-calibrator/ColorSpace.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ using namespace aliases;

namespace ColorSpaceMath
{
enum PRIMARIES { SRGB = 0, BT_2020, WIDE_GAMMUT };
enum PRIMARIES { SRGB = 0, BT_2020, WIDE_GAMMUT };

QString gammaToString(HDR_GAMMA gamma);

Expand Down Expand Up @@ -85,6 +85,8 @@ namespace ColorSpaceMath

double3 bt2020_linear_to_nonlinear(double3 input);

double srgb_nonlinear_to_linear(double input);

double3 srgb_nonlinear_to_linear(double3 input);

double3 srgb_linear_to_nonlinear(double3 input);
Expand Down
2 changes: 1 addition & 1 deletion include/lut-calibrator/LutCalibrator.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ namespace linalg {
}

namespace ColorSpaceMath {
enum HDR_GAMMA { PQ = 0, HLG, sRGB, BT2020inSRGB, PQinSRGB};
enum HDR_GAMMA { PQ = 0, HLG, sRGB, BT2020inSRGB, PQinSRGB, P010 };
}

struct BestResult;
Expand Down
35 changes: 30 additions & 5 deletions sources/grabber/linux/v4l2/V4L2Grabber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,30 @@
// some stuff for HDR tone mapping
#define LUT_FILE_SIZE 50331648

namespace
{
#ifdef V4L2_PIX_FMT_P010
#pragma message "P010 is supported on the build machine"
bool supportedP010 = true;
#else
#pragma message "P010 is NOT supported on the build machine"
bool supportedP010 = false;
#endif
};

#ifndef V4L2_PIX_FMT_P010
#define V4L2_PIX_FMT_P010 v4l2_fourcc('P', '0', '1', '0')
#endif

static const V4L2Grabber::HyperHdrFormat supportedFormats[] =
{
{ V4L2_PIX_FMT_YUYV, PixelFormat::YUYV },
{ V4L2_PIX_FMT_XRGB32, PixelFormat::XRGB },
{ V4L2_PIX_FMT_RGB24, PixelFormat::RGB24 },
{ V4L2_PIX_FMT_YUV420, PixelFormat::I420 },
{ V4L2_PIX_FMT_NV12, PixelFormat::NV12 },
{ V4L2_PIX_FMT_MJPEG, PixelFormat::MJPEG }
#ifdef V4L2_PIX_FMT_P010
,{ V4L2_PIX_FMT_P010, PixelFormat::P010 }
#endif
{ V4L2_PIX_FMT_MJPEG, PixelFormat::MJPEG },
{ V4L2_PIX_FMT_P010, PixelFormat::P010 }
};


Expand All @@ -84,6 +97,8 @@ V4L2Grabber::V4L2Grabber(const QString& device, const QString& configurationPath
{
// Refresh devices
getV4L2devices();

Debug(_log, "P010 was %s on the build machine", (supportedP010) ? "supported" : "unsupported");
}

QString V4L2Grabber::GetSharedLut()
Expand Down Expand Up @@ -132,7 +147,8 @@ void V4L2Grabber::setHdrToneMappingEnabled(int mode)
{
Debug(_log, "setHdrToneMappingMode replacing LUT and restarting");
_V4L2WorkerManager.Stop();
if ((_actualVideoFormat == PixelFormat::YUYV) || (_actualVideoFormat == PixelFormat::I420) || (_actualVideoFormat == PixelFormat::NV12) || (_actualVideoFormat == PixelFormat::MJPEG))
if ((_actualVideoFormat == PixelFormat::YUYV) || (_actualVideoFormat == PixelFormat::I420) || (_actualVideoFormat == PixelFormat::NV12)
|| (_actualVideoFormat == PixelFormat::P010) || (_actualVideoFormat == PixelFormat::MJPEG))
loadLutFile(PixelFormat::YUYV);
else
loadLutFile(PixelFormat::RGB24);
Expand Down Expand Up @@ -985,6 +1001,15 @@ bool V4L2Grabber::init_device(QString selectedDeviceName, DevicePropertiesItem p
}
break;

case V4L2_PIX_FMT_P010:
{
loadLutFile(PixelFormat::YUYV);
_actualVideoFormat = PixelFormat::P010;
_frameByteSize = (props.x * props.y * 6) / 2;
Info(_log, "Video pixel format is set to: P010");
}
break;

case V4L2_PIX_FMT_NV12:
{
loadLutFile(PixelFormat::YUYV);
Expand Down
10 changes: 9 additions & 1 deletion sources/grabber/windows/MF/MFGrabber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ void MFGrabber::setHdrToneMappingEnabled(int mode)
{
Debug(_log, "setHdrToneMappingMode replacing LUT and restarting");
_MFWorkerManager.Stop();
if ((_actualVideoFormat == PixelFormat::YUYV) || (_actualVideoFormat == PixelFormat::I420) || (_actualVideoFormat == PixelFormat::NV12) || (_actualVideoFormat == PixelFormat::MJPEG))
if ((_actualVideoFormat == PixelFormat::YUYV) || (_actualVideoFormat == PixelFormat::I420) || (_actualVideoFormat == PixelFormat::P010) || (_actualVideoFormat == PixelFormat::NV12) || (_actualVideoFormat == PixelFormat::MJPEG))
loadLutFile(PixelFormat::YUYV);
else
loadLutFile(PixelFormat::RGB24);
Expand Down Expand Up @@ -869,6 +869,14 @@ bool MFGrabber::init_device(QString selectedDeviceName, DevicePropertiesItem pro
}
break;

case PixelFormat::P010:
{
loadLutFile(PixelFormat::YUYV);
_frameByteSize = (6 * props.x * props.y) / 2;
_lineLength = props.x * 2;
}
break;

case PixelFormat::RGB24:
{
loadLutFile(PixelFormat::RGB24);
Expand Down
2 changes: 2 additions & 0 deletions sources/lut-calibrator/ColorSpace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ namespace ColorSpaceMath
return "BT2020 with sRGB TRC";
else if (gamma == HDR_GAMMA::PQinSRGB)
return "PQ in SRGB";
else if (gamma == HDR_GAMMA::P010)
return "P010";
return "UNKNOWN";
}

Expand Down
72 changes: 62 additions & 10 deletions sources/lut-calibrator/LutCalibrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,25 @@ LutCalibrator::~LutCalibrator()
Info(_log, "The calibration object is deleted");
}

static void unpackP010(double *y, double *u, double *v)
{
if (y !=nullptr)
{
*y = *y / 1.5;
}

for (auto chroma : { u, v })
if (chroma != nullptr)
{
double val = (*chroma - (128.0/255.0)) / 1.5;
*chroma = (128.0 / 255.0) + val;
}
};

static void unpackP010(double3& yuv)
{
unpackP010(&yuv.x, &yuv.y, &yuv.z);
};

void LutCalibrator::cancelCalibrationSafe()
{
Expand Down Expand Up @@ -302,6 +321,7 @@ void LutCalibrator::startHandler()

_capturedColors.reset();
_capturedColors = std::make_shared<CapturedColors>();
bestResult = std::make_shared<BestResult>();

if (setTestData())
{
Expand Down Expand Up @@ -406,11 +426,15 @@ void LutCalibrator::handleImage(const Image<ColorRgb>& image)
}

auto pixelFormat = image.getOriginFormat();
if (pixelFormat != PixelFormat::NV12 && pixelFormat != PixelFormat::MJPEG && pixelFormat != PixelFormat::YUYV)
if (pixelFormat != PixelFormat::NV12 && pixelFormat != PixelFormat::MJPEG && pixelFormat != PixelFormat::YUYV && pixelFormat != PixelFormat::P010)
{
error("Only NV12/MJPEG/YUYV video format for the USB grabber and NV12 for the flatbuffers source are supported for the LUT calibration.");
error("Only NV12/MJPEG/YUYV/P010 video format for the USB grabber and NV12 for the flatbuffers source are supported for the LUT calibration.");
return;
}
else if (pixelFormat == PixelFormat::P010)
{
bestResult->signal.isSourceP010 = true;
}

int boardIndex = -1;

Expand Down Expand Up @@ -663,6 +687,11 @@ static double3 hdr_to_srgb(const YuvConverter* _yuvConverter, double3 yuv, const
double3 srgb;
bool white = true;

if (gamma == HDR_GAMMA::P010)
{
unpackP010(yuv);
}

if (gamma == HDR_GAMMA::sRGB || gamma == HDR_GAMMA::BT2020inSRGB)
{
CapturedColors::correctYRange(yuv, signal.yRange, signal.upYLimit, signal.downYLimit, signal.yShift);
Expand All @@ -689,7 +718,7 @@ static double3 hdr_to_srgb(const YuvConverter* _yuvConverter, double3 yuv, const

double3 e;

if (gamma == HDR_GAMMA::PQ)
if (gamma == HDR_GAMMA::PQ || gamma == HDR_GAMMA::P010)
{
e = PQ_ST2084(10000.0 / nits, a);
}
Expand Down Expand Up @@ -1094,9 +1123,13 @@ void LutCalibrator::fineTune(bool precise)
sampleColors[SampleColor::LOW_GREEN] = (std::pair<double3, byte2>(sampleGreenLow.getInputYuvColors().front().first, byte2{ sampleGreenLow.U(), sampleGreenLow.V() }));
sampleColors[SampleColor::LOW_BLUE] = (std::pair<double3, byte2>(sampleBlueLow.getInputYuvColors().front().first, byte2{ sampleBlueLow.U(), sampleBlueLow.V() }));

for (int gamma = (precise) ? bestResult->gamma : HDR_GAMMA::PQ; gamma <= HDR_GAMMA::PQinSRGB; gamma++)
for (int gamma = (precise) ? (bestResult->gamma) : ((bestResult->signal.isSourceP010) ? HDR_GAMMA::P010 : HDR_GAMMA::PQ);
gamma <= HDR_GAMMA::P010; gamma++)
{
std::vector<double> gammasHLG;

if (gamma == HDR_GAMMA::P010 && !bestResult->signal.isSourceP010)
continue;

if (gamma == HDR_GAMMA::HLG)
{
Expand All @@ -1116,6 +1149,13 @@ void LutCalibrator::fineTune(bool precise)
{
NITS = 10000.0 * PQ_ST2084(1.0, maxLevel);
}
else if (gamma == HDR_GAMMA::P010)
{
double unpackWhite = white;
unpackP010(&unpackWhite, nullptr, nullptr);
maxLevel = (unpackWhite - 16.0) / (235.0 - 16.0);
NITS = 10000.0 * PQ_ST2084(1.0, maxLevel);
}
else if (gamma == HDR_GAMMA::PQinSRGB)
{
NITS = 10000.0 * PQ_ST2084(1.0, srgb_linear_to_nonlinear(maxLevel));
Expand Down Expand Up @@ -1230,11 +1270,12 @@ void LutCalibrator::calibration()
{
Debug(_log, "Selected nits: %f", (bestResult->gamma == HDR_GAMMA::HLG) ? 1000.0 * (1 / bestResult->nits) : bestResult->nits);
}
Debug(_log, "Selected bt2020 gamma range: %i", bestResult->bt2020Range);
Debug(_log, "Selected alternative conversion of primaries: %i", bestResult->altConvert);
Debug(_log, "Selected bt2020 gamma range: %s", (bestResult->bt2020Range) ? "yes" : "no");
Debug(_log, "Selected alternative conversion of primaries: %s", (bestResult->altConvert) ? "yes" : "no");
Debug(_log, "Selected aspect: %f %f %f", bestResult->aspect.x, bestResult->aspect.y, bestResult->aspect.z);
Debug(_log, "Selected color aspect mode: %i", bestResult->coloredAspectMode);
Debug(_log, "Selected color aspect: %s %s", QSTRING_CSTR(vecToString(bestResult->colorAspect.first)), QSTRING_CSTR(vecToString(bestResult->colorAspect.second)));
Debug(_log, "Selected source is P010: %s", (bestResult->signal.isSourceP010) ? "yes" : "no");

if (_debug)
{
Expand Down Expand Up @@ -1423,6 +1464,11 @@ void CreateLutWorker::run()
}
else
{
if (bestResult->signal.isSourceP010)
{
unpackP010(yuv);
}

yuv = yuvConverter->toRgb(bestResult->signal.range, bestResult->coef, yuv);
}

Expand Down Expand Up @@ -1543,8 +1589,7 @@ void LutCalibrator::calibrate()
{
emit GlobalSignals::getInstance()->SignalRequestComponent(hyperhdr::Components::COMP_FLATBUFSERVER, -1, false);
}

bestResult = std::make_shared<BestResult>();

_capturedColors->finilizeBoard();


Expand Down Expand Up @@ -1577,9 +1622,16 @@ void LutCalibrator::capturedPrimariesCorrection(ColorSpaceMath::HDR_GAMMA gamma,

for (auto& c : capturedPrimaries)
{
auto a = _yuvConverter->toRgb(_capturedColors->getRange(), YuvConverter::YUV_COEFS(coef), c.yuv());
auto yuv = c.yuv();

if (gamma == HDR_GAMMA::P010)
{
unpackP010(yuv);
}

auto a = _yuvConverter->toRgb(_capturedColors->getRange(), YuvConverter::YUV_COEFS(coef), yuv);

if (gamma == ColorSpaceMath::HDR_GAMMA::PQ)
if (gamma == ColorSpaceMath::HDR_GAMMA::PQ || gamma == ColorSpaceMath::HDR_GAMMA::P010)
{
a = PQ_ST2084(10000.0 / nits, a);
}
Expand Down
1 change: 1 addition & 0 deletions sources/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ add_library(hyperhdr-utils OBJECT ${Utils_SOURCES})
target_link_libraries(hyperhdr-utils
Qt${Qt_VERSION}::Core
Qt${Qt_VERSION}::Network
linalg
)

if(USE_PRECOMPILED_HEADERS AND COMMAND target_precompile_headers)
Expand Down
Loading

0 comments on commit b04b49b

Please sign in to comment.