diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-03-13 16:46:50 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-03-13 16:46:50 +0000 |
| commit | 45625f3116a09d3c8415a54bf8d19fdbb3a3aa9b (patch) | |
| tree | 3619eb2ba2d9e754f9122b367f4eeffe56239bf9 /src | |
| parent | 6e5411a943ef9b3f23cfb8dd9dcc1a756b55bfbe (diff) | |
Compute LUTs at run-time.dynamic-lut
Diffstat (limited to 'src')
| -rw-r--r-- | src/gamma_lut.cc | 16 | ||||
| -rw-r--r-- | src/gamma_lut.h | 13 | ||||
| -rw-r--r-- | src/lut.h | 63 | ||||
| -rw-r--r-- | src/lut_cache.h | 28 | ||||
| -rw-r--r-- | src/picture_frame.cc | 12 | ||||
| -rw-r--r-- | src/picture_frame.h | 4 | ||||
| -rw-r--r-- | src/util.cc | 40 | ||||
| -rw-r--r-- | src/util.h | 4 | ||||
| -rw-r--r-- | src/wscript | 3 | ||||
| -rw-r--r-- | src/xyz_srgb_lut.cc | 24 | ||||
| -rw-r--r-- | src/xyz_srgb_lut.h | 13 |
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; } @@ -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; +}; + +} |
