summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gamma_lut.cc16
-rw-r--r--src/gamma_lut.h13
-rw-r--r--src/lut.h63
-rw-r--r--src/lut_cache.h28
-rw-r--r--src/picture_frame.cc12
-rw-r--r--src/picture_frame.h4
-rw-r--r--src/util.cc40
-rw-r--r--src/util.h4
-rw-r--r--src/wscript3
-rw-r--r--src/xyz_srgb_lut.cc24
-rw-r--r--src/xyz_srgb_lut.h13
11 files changed, 198 insertions, 22 deletions
diff --git a/src/gamma_lut.cc b/src/gamma_lut.cc
new file mode 100644
index 00000000..acc80af0
--- /dev/null
+++ b/src/gamma_lut.cc
@@ -0,0 +1,16 @@
+#include <cmath>
+#include "gamma_lut.h"
+#include "lut_cache.h"
+
+using namespace libdcp;
+
+LUTCache<GammaLUT> GammaLUT::cache;
+
+GammaLUT::GammaLUT(int bits, float gamma)
+ : LUT<float> (bits, gamma)
+{
+ int const bit_length = pow(2, bits);
+ for (int i = 0; i < bit_length; ++i) {
+ _lut[i] = pow(float(i) / (bit_length - 1), gamma);
+ }
+}
diff --git a/src/gamma_lut.h b/src/gamma_lut.h
new file mode 100644
index 00000000..e41cd21f
--- /dev/null
+++ b/src/gamma_lut.h
@@ -0,0 +1,13 @@
+#include "lut.h"
+#include "lut_cache.h"
+
+namespace libdcp {
+
+class GammaLUT : public LUT<float>
+{
+public:
+ GammaLUT (int bit_length, float gamma);
+ static LUTCache<GammaLUT> cache;
+};
+
+}
diff --git a/src/lut.h b/src/lut.h
new file mode 100644
index 00000000..8363e6a4
--- /dev/null
+++ b/src/lut.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2012 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.
+
+*/
+
+#ifndef LIBDCP_LUT_H
+#define LIBDCP_LUT_H
+
+#include <cmath>
+
+namespace libdcp {
+
+template<typename T>
+class LUT
+{
+public:
+ LUT(int bit_depth, float gamma)
+ : _lut(0)
+ , _bit_depth (bit_depth)
+ , _gamma (gamma)
+ {
+ _lut = new T[int(std::pow(2, _bit_depth))];
+ }
+
+ virtual ~LUT() {
+ delete[] _lut;
+ }
+
+ T const * lut() const {
+ return _lut;
+ }
+
+ int bit_depth () const {
+ return _bit_depth;
+ }
+
+ float gamma () const {
+ return _gamma;
+ }
+
+protected:
+ T* _lut;
+ int _bit_depth;
+ float _gamma;
+};
+
+}
+
+#endif
diff --git a/src/lut_cache.h b/src/lut_cache.h
new file mode 100644
index 00000000..b60ee109
--- /dev/null
+++ b/src/lut_cache.h
@@ -0,0 +1,28 @@
+#ifndef LIBDCP_LUT_CACHE_H
+#define LIBDCP_LUT_CACHE_H
+
+#include <list>
+#include <boost/shared_ptr.hpp>
+
+template<class T>
+class LUTCache
+{
+public:
+ boost::shared_ptr<T> get (int bit_depth, float gamma)
+ {
+ for (typename std::list<boost::shared_ptr<T> >::iterator i = _cache.begin(); i != _cache.end(); ++i) {
+ if ((*i)->bit_depth() == bit_depth && (*i)->gamma() == gamma) {
+ return *i;
+ }
+ }
+
+ boost::shared_ptr<T> lut (new T (bit_depth, gamma));
+ _cache.push_back (lut);
+ return lut;
+ }
+
+private:
+ std::list<boost::shared_ptr<T> > _cache;
+};
+
+#endif
diff --git a/src/picture_frame.cc b/src/picture_frame.cc
index 907f70ab..5d5f12c2 100644
--- a/src/picture_frame.cc
+++ b/src/picture_frame.cc
@@ -25,6 +25,10 @@
#include "argb_frame.h"
#include "lut.h"
#include "util.h"
+#include "gamma_lut.h"
+#include "xyz_srgb_lut.h"
+
+#define DCI_GAMMA 2.6
using std::string;
using boost::shared_ptr;
@@ -76,11 +80,11 @@ MonoPictureFrame::j2k_size () const
*
*/
shared_ptr<ARGBFrame>
-MonoPictureFrame::argb_frame (int reduce) const
+MonoPictureFrame::argb_frame (int reduce, float srgb_gamma) const
{
opj_image_t* xyz_frame = decompress_j2k (const_cast<uint8_t*> (_buffer->RoData()), _buffer->Size(), reduce);
assert (xyz_frame->numcomps == 3);
- shared_ptr<ARGBFrame> f = xyz_to_rgb (xyz_frame);
+ shared_ptr<ARGBFrame> f = xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), XYZsRGBLUT::cache.get (12, srgb_gamma));
opj_image_destroy (xyz_frame);
return f;
}
@@ -122,7 +126,7 @@ StereoPictureFrame::~StereoPictureFrame ()
*
*/
shared_ptr<ARGBFrame>
-StereoPictureFrame::argb_frame (Eye eye, int reduce) const
+StereoPictureFrame::argb_frame (Eye eye, int reduce, float srgb_gamma) const
{
opj_image_t* xyz_frame = 0;
switch (eye) {
@@ -135,7 +139,7 @@ StereoPictureFrame::argb_frame (Eye eye, int reduce) const
}
assert (xyz_frame->numcomps == 3);
- shared_ptr<ARGBFrame> f = xyz_to_rgb (xyz_frame);
+ shared_ptr<ARGBFrame> f = xyz_to_rgb (xyz_frame, GammaLUT::cache.get (12, DCI_GAMMA), XYZsRGBLUT::cache.get (12, srgb_gamma));
opj_image_destroy (xyz_frame);
return f;
}
diff --git a/src/picture_frame.h b/src/picture_frame.h
index 20ce069e..42c5d629 100644
--- a/src/picture_frame.h
+++ b/src/picture_frame.h
@@ -40,7 +40,7 @@ public:
MonoPictureFrame (std::string mxf_path, int n);
~MonoPictureFrame ();
- boost::shared_ptr<ARGBFrame> argb_frame (int reduce = 0) const;
+ boost::shared_ptr<ARGBFrame> argb_frame (int reduce = 0, float srgb_gamma = 2.4) const;
uint8_t const * j2k_data () const;
int j2k_size () const;
@@ -55,7 +55,7 @@ public:
StereoPictureFrame (std::string mxf_path, int n);
~StereoPictureFrame ();
- boost::shared_ptr<ARGBFrame> argb_frame (Eye eye, int reduce = 0) const;
+ boost::shared_ptr<ARGBFrame> argb_frame (Eye eye, int reduce = 0, float srgb_gamma = 2.4) const;
uint8_t const * left_j2k_data () const;
int left_j2k_size () const;
uint8_t const * right_j2k_data () const;
diff --git a/src/util.cc b/src/util.cc
index 1cbec719..bd5f32ed 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -34,7 +34,8 @@
#include "exceptions.h"
#include "types.h"
#include "argb_frame.h"
-#include "lut.h"
+#include "gamma_lut.h"
+#include "xyz_srgb_lut.h"
using std::string;
using std::stringstream;
@@ -202,8 +203,19 @@ libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
* @return RGB image.
*/
shared_ptr<ARGBFrame>
-libdcp::xyz_to_rgb (opj_image_t* xyz_frame)
+libdcp::xyz_to_rgb (opj_image_t* xyz_frame, shared_ptr<const GammaLUT> lut_in, shared_ptr<const XYZsRGBLUT> lut_out)
{
+ float const dci_coefficient = 48.0 / 52.37;
+
+ /* sRGB color matrix for XYZ -> RGB */
+ float const colour_matrix[3][3] = {
+ { 3.240454836, -1.537138850, -0.498531547},
+ {-0.969266390, 1.876010929, 0.041556082},
+ { 0.055643420, -0.204025854, 1.057225162}
+ };
+
+ int const max_colour = pow (2, lut_out->bit_depth()) - 1;
+
struct {
double x, y, z;
} s;
@@ -227,19 +239,19 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame)
assert (*xyz_x >= 0 && *xyz_y >= 0 && *xyz_z >= 0 && *xyz_x < 4096 && *xyz_x < 4096 && *xyz_z < 4096);
/* In gamma LUT */
- s.x = lut_in[*xyz_x++];
- s.y = lut_in[*xyz_y++];
- s.z = lut_in[*xyz_z++];
+ s.x = lut_in->lut()[*xyz_x++];
+ s.y = lut_in->lut()[*xyz_y++];
+ 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 * color_matrix[0][0]) + (s.y * color_matrix[0][1]) + (s.z * color_matrix[0][2]));
- d.g = ((s.x * color_matrix[1][0]) + (s.y * color_matrix[1][1]) + (s.z * color_matrix[1][2]));
- d.b = ((s.x * color_matrix[2][0]) + (s.y * color_matrix[2][1]) + (s.z * color_matrix[2][2]));
+ 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 = min (d.r, 1.0);
d.r = max (d.r, 0.0);
@@ -251,9 +263,9 @@ libdcp::xyz_to_rgb (opj_image_t* xyz_frame)
d.b = max (d.b, 0.0);
/* Out gamma LUT */
- *argb_line++ = lut_out[(int) (d.b * COLOR_DEPTH)];
- *argb_line++ = lut_out[(int) (d.g * COLOR_DEPTH)];
- *argb_line++ = lut_out[(int) (d.r * COLOR_DEPTH)];
+ *argb_line++ = lut_out->lut()[(int) (d.b * max_colour)];
+ *argb_line++ = lut_out->lut()[(int) (d.g * max_colour)];
+ *argb_line++ = lut_out->lut()[(int) (d.r * max_colour)];
*argb_line++ = 0xff;
}
diff --git a/src/util.h b/src/util.h
index f5685970..2036a7ce 100644
--- a/src/util.h
+++ b/src/util.h
@@ -33,6 +33,8 @@
namespace libdcp {
class ARGBFrame;
+class GammaLUT;
+class XYZsRGBLUT;
struct Size {
Size ()
@@ -58,7 +60,7 @@ extern std::string content_kind_to_string (ContentKind kind);
extern ContentKind content_kind_from_string (std::string kind);
extern bool empty_or_white_space (std::string s);
extern opj_image_t* decompress_j2k (uint8_t* data, int64_t size, int reduce);
-extern boost::shared_ptr<ARGBFrame> xyz_to_rgb (opj_image_t* xyz_frame);
+extern boost::shared_ptr<ARGBFrame> xyz_to_rgb (opj_image_t* xyz_frame, boost::shared_ptr<const GammaLUT>, boost::shared_ptr<const XYZsRGBLUT>);
}
diff --git a/src/wscript b/src/wscript
index d243ae46..efba2502 100644
--- a/src/wscript
+++ b/src/wscript
@@ -15,7 +15,7 @@ def build(bld):
cpl_file.cc
dcp.cc
dcp_time.cc
- lut.cc
+ gamma_lut.cc
metadata.cc
mxf_asset.cc
picture_asset.cc
@@ -31,6 +31,7 @@ def build(bld):
util.cc
version.cc
xml.cc
+ xyz_srgb_lut.cc
"""
headers = """
diff --git a/src/xyz_srgb_lut.cc b/src/xyz_srgb_lut.cc
new file mode 100644
index 00000000..3d207195
--- /dev/null
+++ b/src/xyz_srgb_lut.cc
@@ -0,0 +1,24 @@
+#include <iostream>
+#include <cmath>
+#include "xyz_srgb_lut.h"
+
+using namespace libdcp;
+
+LUTCache<XYZsRGBLUT> XYZsRGBLUT::cache;
+
+XYZsRGBLUT::XYZsRGBLUT(int bits, float gamma)
+ : LUT<int> (bits, gamma)
+{
+ int const bit_length = pow(2, bits);
+
+ for (int i = 0; i < bit_length; ++i) {
+ float v = float(i) / (bit_length - 1);
+ if (v < (0.04045 / 12.92)) {
+ v *= 12.92;
+ } else {
+ v = (1.055 * pow (v, (1 / gamma))) - 0.055;
+ }
+
+ _lut[i] = int(v * 255);
+ }
+}
diff --git a/src/xyz_srgb_lut.h b/src/xyz_srgb_lut.h
new file mode 100644
index 00000000..63f89178
--- /dev/null
+++ b/src/xyz_srgb_lut.h
@@ -0,0 +1,13 @@
+#include "lut.h"
+#include "lut_cache.h"
+
+namespace libdcp {
+
+class XYZsRGBLUT : public LUT<int>
+{
+public:
+ XYZsRGBLUT(int colour_depth, float gamma);
+ static LUTCache<XYZsRGBLUT> cache;
+};
+
+}