summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-07-12 22:37:08 +0100
committerCarl Hetherington <cth@carlh.net>2013-07-12 22:37:08 +0100
commit749011eb81eeb8f0fbe74055c005b61cc8b1fb9a (patch)
treefa637fdbbae050dc840396bce9d6c00cb219d485 /src
parent414c44166031003b29d1b0b2fd2c9748a63260b4 (diff)
Support rgb -> xyz encoding.
Diffstat (limited to 'src')
-rw-r--r--src/colour_matrix.cc42
-rw-r--r--src/colour_matrix.h30
-rw-r--r--src/gamma_lut.cc2
-rw-r--r--src/gamma_lut.h2
-rw-r--r--src/lut.h7
-rw-r--r--src/rec709_linearised_gamma_lut.cc2
-rw-r--r--src/rec709_linearised_gamma_lut.h2
-rw-r--r--src/rgb_xyz.cc87
-rw-r--r--src/rgb_xyz.h9
-rw-r--r--src/srgb_linearised_gamma_lut.cc2
-rw-r--r--src/srgb_linearised_gamma_lut.h2
-rw-r--r--src/wscript5
-rw-r--r--src/xyz_frame.cc29
-rw-r--r--src/xyz_frame.h1
14 files changed, 190 insertions, 32 deletions
diff --git a/src/colour_matrix.cc b/src/colour_matrix.cc
new file mode 100644
index 00000000..47ebf3e0
--- /dev/null
+++ b/src/colour_matrix.cc
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "colour_matrix.h"
+
+/* sRGB color matrix for XYZ -> RGB. This is the same as the one used by the Fraunhofer
+ EasyDCP player, I think.
+*/
+
+float const libdcp::colour_matrix::xyz_to_rgb[3][3] = {
+ { 3.24096989631653, -1.5373831987381, -0.498610764741898 },
+ { -0.96924364566803, 1.87596750259399, 0.0415550582110882 },
+ { 0.0556300804018974, -0.203976958990097, 1.05697154998779 }
+};
+
+float const libdcp::colour_matrix::srgb_to_xyz[3][3] = {
+ {0.4124564, 0.3575761, 0.1804375},
+ {0.2126729, 0.7151522, 0.0721750},
+ {0.0193339, 0.1191920, 0.9503041}
+};
+
+float const libdcp::colour_matrix::rec709_to_xyz[3][3] = {
+ {0.4124564, 0.3575761, 0.1804375},
+ {0.2126729, 0.7151522, 0.0721750},
+ {0.0193339, 0.1191920, 0.9503041}
+};
diff --git a/src/colour_matrix.h b/src/colour_matrix.h
new file mode 100644
index 00000000..13bbc821
--- /dev/null
+++ b/src/colour_matrix.h
@@ -0,0 +1,30 @@
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+namespace libdcp {
+
+namespace colour_matrix {
+
+extern float const xyz_to_rgb[3][3];
+extern float const srgb_to_xyz[3][3];
+extern float const rec709_to_xyz[3][3];
+
+}
+
+}
diff --git a/src/gamma_lut.cc b/src/gamma_lut.cc
index 547601b9..80d9b902 100644
--- a/src/gamma_lut.cc
+++ b/src/gamma_lut.cc
@@ -26,7 +26,7 @@ using namespace libdcp;
LUTCache<GammaLUT> GammaLUT::cache;
GammaLUT::GammaLUT(int bits, float gamma)
- : LUT<float> (bits, gamma)
+ : LUT (bits, gamma)
{
int const bit_length = pow(2, bits);
for (int i = 0; i < bit_length; ++i) {
diff --git a/src/gamma_lut.h b/src/gamma_lut.h
index c844de44..32e4af02 100644
--- a/src/gamma_lut.h
+++ b/src/gamma_lut.h
@@ -25,7 +25,7 @@
namespace libdcp {
-class GammaLUT : public LUT<float>
+class GammaLUT : public LUT
{
public:
GammaLUT (int bit_length, float gamma);
diff --git a/src/lut.h b/src/lut.h
index bdb5f37f..3efcaaed 100644
--- a/src/lut.h
+++ b/src/lut.h
@@ -24,7 +24,6 @@
namespace libdcp {
-template<typename T>
class LUT
{
public:
@@ -33,14 +32,14 @@ public:
, _bit_depth (bit_depth)
, _gamma (gamma)
{
- _lut = new T[int(std::pow(2.0f, _bit_depth))];
+ _lut = new float[int(std::pow(2.0f, _bit_depth))];
}
virtual ~LUT() {
delete[] _lut;
}
- T const * lut() const {
+ float const * lut() const {
return _lut;
}
@@ -53,7 +52,7 @@ public:
}
protected:
- T* _lut;
+ float* _lut;
int _bit_depth;
float _gamma;
};
diff --git a/src/rec709_linearised_gamma_lut.cc b/src/rec709_linearised_gamma_lut.cc
index f1ac0a6d..f14e4472 100644
--- a/src/rec709_linearised_gamma_lut.cc
+++ b/src/rec709_linearised_gamma_lut.cc
@@ -24,7 +24,7 @@ using namespace libdcp;
LUTCache<Rec709LinearisedGammaLUT> Rec709LinearisedGammaLUT::cache;
Rec709LinearisedGammaLUT::Rec709LinearisedGammaLUT (int bits, float gamma)
- : LUT<float> (bits, gamma)
+ : LUT (bits, gamma)
{
int const bit_length = pow (2, bits);
for (int i = 0; i < bit_length; ++i) {
diff --git a/src/rec709_linearised_gamma_lut.h b/src/rec709_linearised_gamma_lut.h
index 75e71f74..af0158a5 100644
--- a/src/rec709_linearised_gamma_lut.h
+++ b/src/rec709_linearised_gamma_lut.h
@@ -22,7 +22,7 @@
namespace libdcp {
-class Rec709LinearisedGammaLUT : public LUT<float>
+class Rec709LinearisedGammaLUT : public LUT
{
public:
Rec709LinearisedGammaLUT (int bit_length, float gamma);
diff --git a/src/rgb_xyz.cc b/src/rgb_xyz.cc
index 6be7180f..22b2bdec 100644
--- a/src/rgb_xyz.cc
+++ b/src/rgb_xyz.cc
@@ -21,31 +21,23 @@
#include "argb_frame.h"
#include "xyz_frame.h"
#include "gamma_lut.h"
+#include "image.h"
+#include "colour_matrix.h"
using std::min;
using std::max;
using boost::shared_ptr;
using namespace libdcp;
+#define DCI_COEFFICIENT (48.0 / 52.37)
+
/** Convert an openjpeg XYZ image to RGB.
* @param xyz_frame Frame in XYZ.
* @return RGB image.
*/
shared_ptr<ARGBFrame>
-libdcp::xyz_to_rgb (shared_ptr<const XYZFrame> xyz_frame, shared_ptr<const GammaLUT> lut_in, shared_ptr<const GammaLUT> lut_out)
+libdcp::xyz_to_rgb (shared_ptr<const XYZFrame> xyz_frame, shared_ptr<const LUT> lut_in, shared_ptr<const LUT> lut_out)
{
- float const dci_coefficient = 48.0 / 52.37;
-
- /* sRGB color matrix for XYZ -> RGB. This is the same as the one used by the Fraunhofer
- EasyDCP player, I think.
- */
-
- float const colour_matrix[3][3] = {
- { 3.24096989631653, -1.5373831987381, -0.498610764741898 },
- { -0.96924364566803, 1.87596750259399, 0.0415550582110882 },
- { 0.0556300804018974, -0.203976958990097, 1.05697154998779 }
- };
-
int const max_colour = pow (2, lut_out->bit_depth()) - 1;
struct {
@@ -76,14 +68,14 @@ libdcp::xyz_to_rgb (shared_ptr<const XYZFrame> xyz_frame, shared_ptr<const Gamma
s.z = lut_in->lut()[*xyz_z++];
/* DCI companding */
- s.x /= dci_coefficient;
- s.y /= dci_coefficient;
- s.z /= dci_coefficient;
-
+ s.x /= DCI_COEFFICIENT;
+ s.y /= DCI_COEFFICIENT;
+ s.z /= DCI_COEFFICIENT;
+
/* XYZ to RGB */
- d.r = ((s.x * colour_matrix[0][0]) + (s.y * colour_matrix[0][1]) + (s.z * colour_matrix[0][2]));
- d.g = ((s.x * colour_matrix[1][0]) + (s.y * colour_matrix[1][1]) + (s.z * colour_matrix[1][2]));
- d.b = ((s.x * colour_matrix[2][0]) + (s.y * colour_matrix[2][1]) + (s.z * colour_matrix[2][2]));
+ d.r = ((s.x * colour_matrix::xyz_to_rgb[0][0]) + (s.y * colour_matrix::xyz_to_rgb[0][1]) + (s.z * colour_matrix::xyz_to_rgb[0][2]));
+ d.g = ((s.x * colour_matrix::xyz_to_rgb[1][0]) + (s.y * colour_matrix::xyz_to_rgb[1][1]) + (s.z * colour_matrix::xyz_to_rgb[1][2]));
+ d.b = ((s.x * colour_matrix::xyz_to_rgb[2][0]) + (s.y * colour_matrix::xyz_to_rgb[2][1]) + (s.z * colour_matrix::xyz_to_rgb[2][2]));
d.r = min (d.r, 1.0);
d.r = max (d.r, 0.0);
@@ -107,3 +99,58 @@ libdcp::xyz_to_rgb (shared_ptr<const XYZFrame> xyz_frame, shared_ptr<const Gamma
return argb_frame;
}
+shared_ptr<libdcp::XYZFrame>
+libdcp::rgb_to_xyz (shared_ptr<const Image> rgb, shared_ptr<const LUT> lut_in, shared_ptr<const LUT> lut_out, float const colour_matrix[3][3])
+{
+ assert (lut_in->bit_depth() == 12);
+ assert (lut_out->bit_depth() == 16);
+
+ shared_ptr<XYZFrame> xyz (new XYZFrame (rgb->size ()));
+
+ struct {
+ double r, g, b;
+ } s;
+
+ struct {
+ double x, y, z;
+ } d;
+
+ int jn = 0;
+ for (int y = 0; y < rgb->size().height; ++y) {
+ uint8_t* p = rgb->data()[0] + y * rgb->stride()[0];
+ for (int x = 0; x < rgb->size().width; ++x) {
+
+ /* In gamma LUT (converting 8-bit input to 12-bit) */
+ s.r = lut_in->lut()[*p++ << 4];
+ s.g = lut_in->lut()[*p++ << 4];
+ s.b = lut_in->lut()[*p++ << 4];
+
+ /* RGB to XYZ Matrix */
+ d.x = ((s.r * colour_matrix[0][0]) +
+ (s.g * colour_matrix[0][1]) +
+ (s.b * colour_matrix[0][2]));
+
+ d.y = ((s.r * colour_matrix[1][0]) +
+ (s.g * colour_matrix[1][1]) +
+ (s.b * colour_matrix[1][2]));
+
+ d.z = ((s.r * colour_matrix[2][0]) +
+ (s.g * colour_matrix[2][1]) +
+ (s.b * colour_matrix[2][2]));
+
+ /* DCI companding */
+ d.x = d.x * DCI_COEFFICIENT * 65535;
+ d.y = d.y * DCI_COEFFICIENT * 65535;
+ d.z = d.z * DCI_COEFFICIENT * 65535;
+
+ /* Out gamma LUT */
+ xyz->data(0)[jn] = lut_out->lut()[(int) d.x] * 4096;
+ xyz->data(1)[jn] = lut_out->lut()[(int) d.y] * 4096;
+ xyz->data(2)[jn] = lut_out->lut()[(int) d.z] * 4096;
+
+ ++jn;
+ }
+ }
+
+ return xyz;
+}
diff --git a/src/rgb_xyz.h b/src/rgb_xyz.h
index 123e055a..d85e5a1f 100644
--- a/src/rgb_xyz.h
+++ b/src/rgb_xyz.h
@@ -23,10 +23,15 @@ namespace libdcp {
class ARGBFrame;
class XYZFrame;
-class GammaLUT;
+class LUT;
+class Image;
extern boost::shared_ptr<ARGBFrame> xyz_to_rgb (
- boost::shared_ptr<const XYZFrame>, boost::shared_ptr<const GammaLUT>, boost::shared_ptr<const GammaLUT>
+ boost::shared_ptr<const XYZFrame>, boost::shared_ptr<const LUT>, boost::shared_ptr<const LUT>
);
+extern boost::shared_ptr<XYZFrame> rgb_to_xyz (
+ boost::shared_ptr<const Image>, boost::shared_ptr<const LUT>, boost::shared_ptr<const LUT>, float const colour_matrix[3][3]
+ );
+
}
diff --git a/src/srgb_linearised_gamma_lut.cc b/src/srgb_linearised_gamma_lut.cc
index 1c10e118..0d3650f4 100644
--- a/src/srgb_linearised_gamma_lut.cc
+++ b/src/srgb_linearised_gamma_lut.cc
@@ -24,7 +24,7 @@ using namespace libdcp;
LUTCache<SRGBLinearisedGammaLUT> SRGBLinearisedGammaLUT::cache;
SRGBLinearisedGammaLUT::SRGBLinearisedGammaLUT (int bits, float gamma)
- : LUT<float> (bits, gamma)
+ : LUT (bits, gamma)
{
int const bit_length = pow (2, bits);
for (int i = 0; i < bit_length; ++i) {
diff --git a/src/srgb_linearised_gamma_lut.h b/src/srgb_linearised_gamma_lut.h
index 9e32463a..34800c66 100644
--- a/src/srgb_linearised_gamma_lut.h
+++ b/src/srgb_linearised_gamma_lut.h
@@ -22,7 +22,7 @@
namespace libdcp {
-class SRGBLinearisedGammaLUT : public LUT<float>
+class SRGBLinearisedGammaLUT : public LUT
{
public:
SRGBLinearisedGammaLUT (int bit_length, float gamma);
diff --git a/src/wscript b/src/wscript
index 3b23443c..4d51bbe4 100644
--- a/src/wscript
+++ b/src/wscript
@@ -13,11 +13,13 @@ def build(bld):
argb_frame.cc
asset.cc
certificates.cc
+ colour_matrix.cc
crypt_chain.cc
cpl.cc
dcp.cc
dcp_time.cc
gamma_lut.cc
+ image.cc
kdm.cc
metadata.cc
mxf_asset.cc
@@ -43,13 +45,16 @@ def build(bld):
headers = """
asset.h
certificates.h
+ colour_matrix.h
cpl.h
crypt_chain.h
dcp.h
dcp_time.h
exceptions.h
gamma_lut.h
+ image.h
kdm.h
+ lut.h
metadata.h
mxf_asset.h
picture_asset.h
diff --git a/src/xyz_frame.cc b/src/xyz_frame.cc
index 78df3f33..f5b0ee86 100644
--- a/src/xyz_frame.cc
+++ b/src/xyz_frame.cc
@@ -18,6 +18,7 @@
*/
#include <cassert>
+#include <stdexcept>
#include "xyz_frame.h"
using namespace libdcp;
@@ -29,6 +30,34 @@ XYZFrame::XYZFrame (opj_image_t* image)
assert (_opj_image->numcomps == 3);
}
+XYZFrame::XYZFrame (Size size)
+{
+ opj_image_cmptparm_t cmptparm[3];
+
+ for (int i = 0; i < 3; ++i) {
+ cmptparm[i].dx = 1;
+ cmptparm[i].dy = 1;
+ cmptparm[i].w = size.width;
+ cmptparm[i].h = size.height;
+ cmptparm[i].x0 = 0;
+ cmptparm[i].y0 = 0;
+ cmptparm[i].prec = 12;
+ cmptparm[i].bpp = 12;
+ cmptparm[i].sgnd = 0;
+ }
+
+ /* XXX: is this _SRGB right? */
+ _opj_image = opj_image_create (3, &cmptparm[0], CLRSPC_SRGB);
+ if (_opj_image == 0) {
+ throw std::runtime_error ("could not create libopenjpeg image");
+ }
+
+ _opj_image->x0 = 0;
+ _opj_image->y0 = 0;
+ _opj_image->x1 = size.width;
+ _opj_image->y1 = size.height;
+}
+
XYZFrame::~XYZFrame ()
{
opj_image_destroy (_opj_image);
diff --git a/src/xyz_frame.h b/src/xyz_frame.h
index 9a10d1e3..a4dcb2c0 100644
--- a/src/xyz_frame.h
+++ b/src/xyz_frame.h
@@ -26,6 +26,7 @@ class XYZFrame
{
public:
XYZFrame (opj_image_t *);
+ XYZFrame (Size);
~XYZFrame ();
int* data (int) const;