diff options
| author | Carl Hetherington <cth@carlh.net> | 2012-08-22 12:32:52 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2012-08-22 12:32:52 +0100 |
| commit | c70373ba74504ae39453c2a41ce1ab047fd441b4 (patch) | |
| tree | 020b40133c93a797341b7a19c46c787f449cebe1 /src | |
| parent | dbdef419973ea00817022a4352126925025857dd (diff) | |
Rough support for 3D.
Diffstat (limited to 'src')
| -rw-r--r-- | src/cpl.cc | 15 | ||||
| -rw-r--r-- | src/cpl.h | 25 | ||||
| -rw-r--r-- | src/dcp.cc | 52 | ||||
| -rw-r--r-- | src/picture_asset.cc | 229 | ||||
| -rw-r--r-- | src/picture_asset.h | 66 | ||||
| -rw-r--r-- | src/picture_frame.cc | 126 | ||||
| -rw-r--r-- | src/picture_frame.h | 25 | ||||
| -rw-r--r-- | src/reel.h | 4 | ||||
| -rw-r--r-- | src/types.h | 6 | ||||
| -rw-r--r-- | src/util.cc | 84 | ||||
| -rw-r--r-- | src/util.h | 7 |
11 files changed, 398 insertions, 241 deletions
@@ -67,7 +67,8 @@ CPLReel::CPLReel (xmlpp::Node const * node) CPLAssetList::CPLAssetList (xmlpp::Node const * node) : XMLNode (node) { - main_picture = sub_node<MainPicture> ("MainPicture"); + main_picture = optional_sub_node<MainPicture> ("MainPicture"); + main_stereoscopic_picture = optional_sub_node<MainStereoscopicPicture> ("MainStereoscopicPicture"); main_sound = optional_sub_node<MainSound> ("MainSound"); main_subtitle = optional_sub_node<MainSubtitle> ("MainSubtitle"); @@ -75,6 +76,18 @@ CPLAssetList::CPLAssetList (xmlpp::Node const * node) } MainPicture::MainPicture (xmlpp::Node const * node) + : Picture (node) +{ + +} + +MainStereoscopicPicture::MainStereoscopicPicture (xmlpp::Node const * node) + : Picture (node) +{ + +} + +Picture::Picture (xmlpp::Node const * node) : XMLNode (node) { id = string_node ("Id"); @@ -27,12 +27,11 @@ namespace libdcp { -/** CPL MainPicture node */ -class MainPicture : public XMLNode +class Picture : public XMLNode { public: - MainPicture () {} - MainPicture (xmlpp::Node const * node); + Picture () {} + Picture (xmlpp::Node const * node); std::string id; std::string annotation_text; @@ -44,6 +43,23 @@ public: Fraction screen_aspect_ratio; }; + +/** CPL MainPicture node */ +class MainPicture : public Picture +{ +public: + MainPicture () {} + MainPicture (xmlpp::Node const * node); +}; + +/** CPL MainStereoscopicPicture node */ +class MainStereoscopicPicture : public Picture +{ +public: + MainStereoscopicPicture () {} + MainStereoscopicPicture (xmlpp::Node const * node); +}; + /** CPL MainSound node */ class MainSound : public XMLNode { @@ -82,6 +98,7 @@ public: CPLAssetList (xmlpp::Node const * node); boost::shared_ptr<MainPicture> main_picture; + boost::shared_ptr<MainStereoscopicPicture> main_stereoscopic_picture; boost::shared_ptr<MainSound> main_sound; boost::shared_ptr<MainSubtitle> main_subtitle; }; @@ -265,24 +265,49 @@ DCP::DCP (string directory) _fps = 0; for (list<shared_ptr<CPLReel> >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) { - assert (_fps == 0 || _fps == (*i)->asset_list->main_picture->frame_rate.numerator); - _fps = (*i)->asset_list->main_picture->frame_rate.numerator; - _length += (*i)->asset_list->main_picture->duration; - string n = pkl->asset_from_id ((*i)->asset_list->main_picture->id)->original_file_name; - if (n.empty ()) { - n = (*i)->asset_list->main_picture->annotation_text; + shared_ptr<Picture> p; + + if ((*i)->asset_list->main_picture) { + p = (*i)->asset_list->main_picture; + } else { + p = (*i)->asset_list->main_stereoscopic_picture; } - shared_ptr<PictureAsset> picture (new PictureAsset ( - _directory, - n, - _fps, - (*i)->asset_list->main_picture->duration - ) - ); + assert (_fps == 0 || _fps == p->frame_rate.numerator); + _fps = p->frame_rate.numerator; + _length += p->duration; + string n = pkl->asset_from_id (p->id)->original_file_name; + if (n.empty ()) { + n = p->annotation_text; + } + + shared_ptr<PictureAsset> picture; shared_ptr<SoundAsset> sound; + shared_ptr<SubtitleAsset> subtitle; + + if ((*i)->asset_list->main_picture) { + + picture.reset (new MonoPictureAsset ( + _directory, + n, + _fps, + (*i)->asset_list->main_picture->duration + ) + ); + + } else if ((*i)->asset_list->main_stereoscopic_picture) { + + picture.reset (new StereoPictureAsset ( + _directory, + n, + _fps, + (*i)->asset_list->main_stereoscopic_picture->duration + ) + ); + + } if ((*i)->asset_list->main_sound) { @@ -302,7 +327,6 @@ DCP::DCP (string directory) assert (files.subtitles.size() < 2); - shared_ptr<SubtitleAsset> subtitle; if (!files.subtitles.empty ()) { string const l = files.subtitles.front().substr (_directory.length ()); subtitle.reset (new SubtitleAsset (_directory, l)); diff --git a/src/picture_asset.cc b/src/picture_asset.cc index dd1853a6..ac6ec05e 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -40,102 +40,10 @@ using namespace std; using namespace boost; using namespace libdcp; -PictureAsset::PictureAsset ( - sigc::slot<string, int> get_path, - string directory, - string mxf_name, - sigc::signal1<void, float>* progress, - int fps, - int length, - int width, - int height) +PictureAsset::PictureAsset (string directory, string mxf_name, sigc::signal1<void, float>* progress, int fps, int length) : MXFAsset (directory, mxf_name, progress, fps, length) - , _width (width) - , _height (height) { - construct (get_path); -} -PictureAsset::PictureAsset ( - vector<string> const & files, - string directory, - string mxf_name, - sigc::signal1<void, float>* progress, - int fps, - int length, - int width, - int height) - : MXFAsset (directory, mxf_name, progress, fps, length) - , _width (width) - , _height (height) -{ - construct (sigc::bind (sigc::mem_fun (*this, &PictureAsset::path_from_list), files)); -} - -PictureAsset::PictureAsset (string directory, string mxf_name, int fps, int length) - : MXFAsset (directory, mxf_name, 0, fps, length) -{ - ASDCP::JP2K::MXFReader reader; - if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { - throw FileError ("could not open MXF file for reading", path().string()); - } - - ASDCP::JP2K::PictureDescriptor desc; - if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) { - throw DCPReadError ("could not read video MXF information"); - } - - _width = desc.StoredWidth; - _height = desc.StoredHeight; - -} - -string -PictureAsset::path_from_list (int f, vector<string> const & files) const -{ - return files[f]; -} - -void -PictureAsset::construct (sigc::slot<string, int> get_path) -{ - ASDCP::JP2K::CodestreamParser j2k_parser; - ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte); - if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (get_path(0).c_str(), frame_buffer))) { - throw FileError ("could not open JPEG2000 file for reading", get_path (0)); - } - - ASDCP::JP2K::PictureDescriptor picture_desc; - j2k_parser.FillPictureDescriptor (picture_desc); - picture_desc.EditRate = ASDCP::Rational (_fps, 1); - - ASDCP::WriterInfo writer_info; - fill_writer_info (&writer_info); - - ASDCP::JP2K::MXFWriter mxf_writer; - if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc))) { - throw FileError ("could not open MXF file for writing", path().string()); - } - - for (int i = 0; i < _length; ++i) { - - string const path = get_path (i); - - if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (path.c_str(), frame_buffer))) { - throw FileError ("could not open JPEG2000 file for reading", path); - } - - /* XXX: passing 0 to WriteFrame ok? */ - if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) { - throw MiscError ("error in writing video MXF"); - } - - (*_progress) (0.5 * float (i) / _length); - } - - if (ASDCP_FAILURE (mxf_writer.Finalize())) { - throw MiscError ("error in finalising video MXF"); - } } void @@ -297,27 +205,128 @@ PictureAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt) const return notes; } -opj_image_t * -PictureAsset::decompress_j2k (uint8_t* data, int64_t size) const +MonoPictureAsset::MonoPictureAsset ( + sigc::slot<string, int> get_path, + string directory, + string mxf_name, + sigc::signal1<void, float>* progress, + int fps, + int length, + int width, + int height) + : PictureAsset (directory, mxf_name, progress, fps, length) +{ + _width = width; + _height = height; + construct (get_path); +} + +MonoPictureAsset::MonoPictureAsset ( + vector<string> const & files, + string directory, + string mxf_name, + sigc::signal1<void, float>* progress, + int fps, + int length, + int width, + int height) + : PictureAsset (directory, mxf_name, progress, fps, length) +{ + _width = width; + _height = height; + construct (sigc::bind (sigc::mem_fun (*this, &MonoPictureAsset::path_from_list), files)); +} + +MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, int length) + : PictureAsset (directory, mxf_name, 0, fps, length) { - opj_dinfo_t* decoder = opj_create_decompress (CODEC_J2K); - opj_dparameters_t parameters; - opj_set_default_decoder_parameters (¶meters); - opj_setup_decoder (decoder, ¶meters); - opj_cio_t* cio = opj_cio_open ((opj_common_ptr) decoder, data, size); - opj_image_t* image = opj_decode (decoder, cio); - if (!image) { - opj_destroy_decompress (decoder); - opj_cio_close (cio); - throw DCPReadError ("could not decode JPEG2000 codestream"); + ASDCP::JP2K::MXFReader reader; + if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { + throw FileError ("could not open MXF file for reading", path().string()); } + + ASDCP::JP2K::PictureDescriptor desc; + if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) { + throw DCPReadError ("could not read video MXF information"); + } + + _width = desc.StoredWidth; + _height = desc.StoredHeight; +} - opj_cio_close (cio); - return image; +void +MonoPictureAsset::construct (sigc::slot<string, int> get_path) +{ + ASDCP::JP2K::CodestreamParser j2k_parser; + ASDCP::JP2K::FrameBuffer frame_buffer (4 * Kumu::Megabyte); + if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (get_path(0).c_str(), frame_buffer))) { + throw FileError ("could not open JPEG2000 file for reading", get_path (0)); + } + + ASDCP::JP2K::PictureDescriptor picture_desc; + j2k_parser.FillPictureDescriptor (picture_desc); + picture_desc.EditRate = ASDCP::Rational (_fps, 1); + + ASDCP::WriterInfo writer_info; + fill_writer_info (&writer_info); + + ASDCP::JP2K::MXFWriter mxf_writer; + if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, picture_desc))) { + throw FileError ("could not open MXF file for writing", path().string()); + } + + for (int i = 0; i < _length; ++i) { + + string const path = get_path (i); + + if (ASDCP_FAILURE (j2k_parser.OpenReadFrame (path.c_str(), frame_buffer))) { + throw FileError ("could not open JPEG2000 file for reading", path); + } + + /* XXX: passing 0 to WriteFrame ok? */ + if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) { + throw MiscError ("error in writing video MXF"); + } + + (*_progress) (0.5 * float (i) / _length); + } + + if (ASDCP_FAILURE (mxf_writer.Finalize())) { + throw MiscError ("error in finalising video MXF"); + } +} + +string +MonoPictureAsset::path_from_list (int f, vector<string> const & files) const +{ + return files[f]; +} + +shared_ptr<const MonoPictureFrame> +MonoPictureAsset::get_frame (int n) const +{ + return shared_ptr<const MonoPictureFrame> (new MonoPictureFrame (path().string(), n)); +} + +StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, int length) + : PictureAsset (directory, mxf_name, 0, fps, length) +{ + ASDCP::JP2K::MXFSReader reader; + if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { + throw FileError ("could not open MXF file for reading", path().string()); + } + + ASDCP::JP2K::PictureDescriptor desc; + if (ASDCP_FAILURE (reader.FillPictureDescriptor (desc))) { + throw DCPReadError ("could not read video MXF information"); + } + + _width = desc.StoredWidth; + _height = desc.StoredHeight; } -shared_ptr<const PictureFrame> -PictureAsset::get_frame (int n) const +shared_ptr<const StereoPictureFrame> +StereoPictureAsset::get_frame (int n) const { - return shared_ptr<const PictureFrame> (new PictureFrame (path().string(), n)); + return shared_ptr<const StereoPictureFrame> (new StereoPictureFrame (path().string(), n)); } diff --git a/src/picture_asset.h b/src/picture_asset.h index f2c4bb34..c21e8cd5 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -27,12 +27,40 @@ namespace libdcp { -class PictureFrame; +class MonoPictureFrame; +class StereoPictureFrame; /** @brief An asset made up of JPEG2000 files */ class PictureAsset : public MXFAsset { public: + PictureAsset (std::string directory, std::string mxf_name, sigc::signal1<void, float>* progress, int fps, int length); + + /** Write details of this asset to a CPL stream. + * @param s Stream. + */ + void write_to_cpl (std::ostream& s) const; + + std::list<std::string> equals (boost::shared_ptr<const Asset> other, EqualityOptions opt) const; + + int width () const { + return _width; + } + + int height () const { + return _height; + } + +protected: + /** picture width in pixels */ + int _width; + /** picture height in pixels */ + int _height; +}; + +class MonoPictureAsset : public PictureAsset +{ +public: /** Construct a PictureAsset, generating the MXF from the JPEG2000 files. * This may take some time; progress is indicated by emission of the Progress signal. * @param files Pathnames of JPEG2000 files, in frame order. @@ -44,7 +72,7 @@ public: * @param width Width of images in pixels. * @param height Height of images in pixels. */ - PictureAsset ( + MonoPictureAsset ( std::vector<std::string> const & files, std::string directory, std::string mxf_name, @@ -66,7 +94,7 @@ public: * @param width Width of images in pixels. * @param height Height of images in pixels. */ - PictureAsset ( + MonoPictureAsset ( sigc::slot<std::string, int> get_path, std::string directory, std::string mxf_name, @@ -77,34 +105,22 @@ public: int height ); - PictureAsset (std::string directory, std::string mxf_name, int fps, int length); + MonoPictureAsset (std::string directory, std::string mxf_name, int fps, int length); - /** Write details of this asset to a CPL stream. - * @param s Stream. - */ - void write_to_cpl (std::ostream& s) const; - - std::list<std::string> equals (boost::shared_ptr<const Asset> other, EqualityOptions opt) const; + boost::shared_ptr<const MonoPictureFrame> get_frame (int n) const; - boost::shared_ptr<const PictureFrame> get_frame (int n) const; - - int width () const { - return _width; - } - - int height () const { - return _height; - } - private: std::string path_from_list (int f, std::vector<std::string> const & files) const; void construct (sigc::slot<std::string, int>); - opj_image_t* decompress_j2k (uint8_t* data, int64_t size) const; +}; + +class StereoPictureAsset : public PictureAsset +{ +public: + StereoPictureAsset (std::string directory, std::string mxf_name, int fps, int length); - /** picture width in pixels */ - int _width; - /** picture height in pixels */ - int _height; + boost::shared_ptr<const StereoPictureFrame> get_frame (int n) const; }; + } diff --git a/src/picture_frame.cc b/src/picture_frame.cc index 09ef4ae4..71a3245c 100644 --- a/src/picture_frame.cc +++ b/src/picture_frame.cc @@ -24,12 +24,13 @@ #include "exceptions.h" #include "argb_frame.h" #include "lut.h" +#include "util.h" using namespace std; using namespace boost; using namespace libdcp; -PictureFrame::PictureFrame (string mxf_path, int n) +MonoPictureFrame::MonoPictureFrame (string mxf_path, int n) { ASDCP::JP2K::MXFReader reader; if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) { @@ -44,106 +45,75 @@ PictureFrame::PictureFrame (string mxf_path, int n) } } -PictureFrame::~PictureFrame () +MonoPictureFrame::~MonoPictureFrame () { delete _buffer; } +#if 0 uint8_t const * -PictureFrame::data () const +MonoPictureFrame::data () const { return _buffer->RoData(); } int -PictureFrame::size () const +MonoPictureFrame::size () const { return _buffer->Size (); } +#endif /** @return An ARGB representation of this frame. This is ARGB in the * Cairo sense, so that each pixel takes up 4 bytes; the first byte * is blue, second green, third red and fourth alpha (always 255). */ shared_ptr<ARGBFrame> -PictureFrame::argb_frame () const +MonoPictureFrame::argb_frame () const { - /* JPEG2000 -> decompressed XYZ */ - - opj_dinfo_t* decoder = opj_create_decompress (CODEC_J2K); - opj_dparameters_t parameters; - opj_set_default_decoder_parameters (¶meters); - opj_setup_decoder (decoder, ¶meters); - opj_cio_t* cio = opj_cio_open ((opj_common_ptr) decoder, const_cast<unsigned char *> (data()), size()); - opj_image_t* xyz_frame = opj_decode (decoder, cio); - if (!xyz_frame) { - opj_destroy_decompress (decoder); - opj_cio_close (cio); - throw DCPReadError ("could not decode JPEG2000 codestream"); - } - + opj_image_t* xyz_frame = decompress_j2k (const_cast<uint8_t*> (_buffer->RoData()), _buffer->Size()); assert (xyz_frame->numcomps == 3); - - /* XYZ -> RGB */ - - struct { - double x, y, z; - } s; - - struct { - double r, g, b; - } d; - - int* xyz_x = xyz_frame->comps[0].data; - int* xyz_y = xyz_frame->comps[1].data; - int* xyz_z = xyz_frame->comps[2].data; + shared_ptr<ARGBFrame> f = xyz_to_rgb (xyz_frame); + opj_image_destroy (xyz_frame); + return f; +} - shared_ptr<ARGBFrame> argb_frame (new ARGBFrame (xyz_frame->x1, xyz_frame->y1)); - - uint8_t* argb = argb_frame->data (); - - for (int y = 0; y < xyz_frame->y1; ++y) { - uint8_t* argb_line = argb; - for (int x = 0; x < xyz_frame->x1; ++x) { - - 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++]; - - /* DCI companding */ - 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 = min (d.r, 1.0); - d.r = max (d.r, 0.0); - - d.g = min (d.g, 1.0); - d.g = max (d.g, 0.0); - - d.b = min (d.b, 1.0); - 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++ = 0xff; - } - - argb += argb_frame->stride (); + +StereoPictureFrame::StereoPictureFrame (string mxf_path, int n) +{ + ASDCP::JP2K::MXFSReader reader; + if (ASDCP_FAILURE (reader.OpenRead (mxf_path.c_str()))) { + throw FileError ("could not open MXF file for reading", mxf_path); + } + + /* XXX: unfortunate guesswork on this buffer size */ + _buffer = new ASDCP::JP2K::SFrameBuffer (4 * Kumu::Megabyte); + + if (ASDCP_FAILURE (reader.ReadFrame (n, *_buffer))) { + throw DCPReadError ("could not read video frame"); + } +} + +StereoPictureFrame::~StereoPictureFrame () +{ + delete _buffer; +} + +shared_ptr<ARGBFrame> +StereoPictureFrame::argb_frame (Eye eye) const +{ + opj_image_t* xyz_frame = 0; + switch (eye) { + case LEFT: + xyz_frame = decompress_j2k (const_cast<uint8_t*> (_buffer->Left.RoData()), _buffer->Left.Size()); + break; + case RIGHT: + xyz_frame = decompress_j2k (const_cast<uint8_t*> (_buffer->Right.RoData()), _buffer->Right.Size()); + break; } - opj_cio_close (cio); + assert (xyz_frame->numcomps == 3); + shared_ptr<ARGBFrame> f = xyz_to_rgb (xyz_frame); opj_image_destroy (xyz_frame); - - return argb_frame; + return f; } diff --git a/src/picture_frame.h b/src/picture_frame.h index 76891d9f..b2693f49 100644 --- a/src/picture_frame.h +++ b/src/picture_frame.h @@ -20,25 +20,24 @@ #include <string> #include <stdint.h> #include <boost/shared_ptr.hpp> +#include "types.h" namespace ASDCP { namespace JP2K { class FrameBuffer; + class SFrameBuffer; } } namespace libdcp { -class ARGBFrame; +class ARGBFrame; -class PictureFrame +class MonoPictureFrame { public: - PictureFrame (std::string mxf_path, int n); - ~PictureFrame (); - - uint8_t const * data () const; - int size () const; + MonoPictureFrame (std::string mxf_path, int n); + ~MonoPictureFrame (); boost::shared_ptr<ARGBFrame> argb_frame () const; @@ -46,4 +45,16 @@ private: ASDCP::JP2K::FrameBuffer* _buffer; }; +class StereoPictureFrame +{ +public: + StereoPictureFrame (std::string mxf_path, int n); + ~StereoPictureFrame (); + + boost::shared_ptr<ARGBFrame> argb_frame (Eye eye) const; + +private: + ASDCP::JP2K::SFrameBuffer* _buffer; +}; + } @@ -23,7 +23,7 @@ namespace libdcp { -class PictureAsset; +class PictureAsset; class SoundAsset; class SubtitleAsset; @@ -43,7 +43,7 @@ public: boost::shared_ptr<const PictureAsset> main_picture () const { return _main_picture; } - + boost::shared_ptr<const SoundAsset> main_sound () const { return _main_sound; } diff --git a/src/types.h b/src/types.h index 280c60cd..98b7c33a 100644 --- a/src/types.h +++ b/src/types.h @@ -64,6 +64,12 @@ enum VAlign CENTER, BOTTOM }; + +enum Eye +{ + EYE_LEFT, + EYE_RIGHT +}; class Fraction { diff --git a/src/util.cc b/src/util.cc index 7138a075..360974a6 100644 --- a/src/util.cc +++ b/src/util.cc @@ -33,9 +33,12 @@ #include "util.h" #include "exceptions.h" #include "types.h" +#include "argb_frame.h" +#include "lut.h" using namespace std; using namespace boost; +using namespace libdcp; string libdcp::make_uuid () @@ -154,3 +157,84 @@ libdcp::ends_with (string big, string little) return big.compare (big.length() - little.length(), little.length(), little) == 0; } + +opj_image_t * +libdcp::decompress_j2k (uint8_t* data, int64_t size) +{ + opj_dinfo_t* decoder = opj_create_decompress (CODEC_J2K); + opj_dparameters_t parameters; + opj_set_default_decoder_parameters (¶meters); + opj_setup_decoder (decoder, ¶meters); + opj_cio_t* cio = opj_cio_open ((opj_common_ptr) decoder, data, size); + opj_image_t* image = opj_decode (decoder, cio); + if (!image) { + opj_destroy_decompress (decoder); + opj_cio_close (cio); + throw DCPReadError ("could not decode JPEG2000 codestream"); + } + + opj_cio_close (cio); + return image; +} + +shared_ptr<ARGBFrame> +libdcp::xyz_to_rgb (opj_image_t* xyz_frame) +{ + struct { + double x, y, z; + } s; + + struct { + double r, g, b; + } d; + + int* xyz_x = xyz_frame->comps[0].data; + int* xyz_y = xyz_frame->comps[1].data; + int* xyz_z = xyz_frame->comps[2].data; + + shared_ptr<ARGBFrame> argb_frame (new ARGBFrame (xyz_frame->x1, xyz_frame->y1)); + + uint8_t* argb = argb_frame->data (); + + for (int y = 0; y < xyz_frame->y1; ++y) { + uint8_t* argb_line = argb; + for (int x = 0; x < xyz_frame->x1; ++x) { + + 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++]; + + /* DCI companding */ + 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 = min (d.r, 1.0); + d.r = max (d.r, 0.0); + + d.g = min (d.g, 1.0); + d.g = max (d.g, 0.0); + + d.b = min (d.b, 1.0); + 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++ = 0xff; + } + + argb += argb_frame->stride (); + } + + return argb_frame; +} @@ -22,11 +22,15 @@ */ #include <string> +#include <stdint.h> #include <sigc++/sigc++.h> +#include <openjpeg.h> #include "types.h" namespace libdcp { +class ARGBFrame; + /** Create a UUID. * @return UUID. */ @@ -44,4 +48,7 @@ extern std::string content_kind_to_string (ContentKind kind); extern ContentKind content_kind_from_string (std::string kind); extern bool ends_with (std::string big, std::string little); +extern opj_image_t* decompress_j2k (uint8_t* data, int64_t size); +extern boost::shared_ptr<ARGBFrame> xyz_to_rgb (opj_image_t* xyz_frame); + } |
