Rough support for 3D.
authorCarl Hetherington <cth@carlh.net>
Wed, 22 Aug 2012 11:32:52 +0000 (12:32 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 22 Aug 2012 11:32:52 +0000 (12:32 +0100)
12 files changed:
src/cpl.cc
src/cpl.h
src/dcp.cc
src/picture_asset.cc
src/picture_asset.h
src/picture_frame.cc
src/picture_frame.h
src/reel.h
src/types.h
src/util.cc
src/util.h
test/tests.cc

index 84bc5997e872f59aa7689bd6c76d8070f9fda2eb..58ee0cce743be77f3db0e65b9100baf817041f05 100644 (file)
@@ -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");
index 0005219a8ae98a6c4f32e6f351b2cc87b2f0cbe4..e06e235121de58e8747fbad9f0af5862c223acce 100644 (file)
--- a/src/cpl.h
+++ b/src/cpl.h
 
 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;
 };
index 3f04d904460a2c74e4f143d7ab6d7bf909f021dc..767ab401c8e62f250fef76a44702b36b42947c49 100644 (file)
@@ -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));
index dd1853a60a23cbc73b5fb1d3c3294afe398242d3..ac6ec05eab2cd344d394823c45251b2e881a107f 100644 (file)
@@ -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 (&parameters);
-       opj_setup_decoder (decoder, &parameters);
-       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));
 }
index f2c4bb34d3adfbc0c9d5c6491f5083672c127e3f..c21e8cd53900d0cad4e59c883ddf38dd5ba5b072 100644 (file)
 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.
@@ -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;
 };
+       
 
 }
index 09ef4ae493fbbd0d499186575b1a71f75182e64e..71a3245c56ecca515475c594ecbc422fb3d8a551 100644 (file)
 #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 (&parameters);
-       opj_setup_decoder (decoder, &parameters);
-       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;
 }
index 76891d9f65cec0852bba65b462e9da567932ec7a..b2693f49e087dc6087dd60ad550679520dbd8455 100644 (file)
 #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;
+};
+
 }
index 28d827f8c3fbedbd195f9bc8957b49c3b7d607fd..2148e122c6b05bc19b943c9645698b94389bab19 100644 (file)
@@ -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;
        }
index 280c60cdea9493a702303dcb33662cd54117685f..98b7c33a49dbcbeaa9fe00067606b641ce93bf35 100644 (file)
@@ -64,6 +64,12 @@ enum VAlign
        CENTER,
        BOTTOM
 };
+
+enum Eye
+{
+       EYE_LEFT,
+       EYE_RIGHT
+};
        
 class Fraction
 {
index 7138a075db5e29ab401a16fba7e631cc2ce0821f..360974a6db5d0fabaa0fe281303be48b1c0d6f71 100644 (file)
 #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 (&parameters);
+       opj_setup_decoder (decoder, &parameters);
+       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;
+}
index 3bbcbabb0057c998c1a85f652393b114698dfdf2..751152721b50ad7fd1a40b53c374e2cea0e1dc6f 100644 (file)
  */
 
 #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);
+
 }
index 2893cc6b3d8d592a548e5226b7deef05d65f0bab..291982ddcc21f00af7597fb92db59595977f6138 100644 (file)
@@ -65,16 +65,16 @@ BOOST_AUTO_TEST_CASE (dcp_test)
        filesystem::create_directories ("build/test/foo");
        libdcp::DCP d ("build/test/foo", "A Test DCP", libdcp::FEATURE, 24, 24);
 
-       shared_ptr<libdcp::PictureAsset> mp (new libdcp::PictureAsset (
-                                                   sigc::ptr_fun (&j2c),
-                                                   "build/test/foo",
-                                                   "video.mxf",
-                                                   &d.Progress,
-                                                   24,
-                                                   24,
-                                                   32,
-                                                   32
-                                                   ));
+       shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset (
+                                                        sigc::ptr_fun (&j2c),
+                                                        "build/test/foo",
+                                                        "video.mxf",
+                                                        &d.Progress,
+                                                        24,
+                                                        24,
+                                                        32,
+                                                        32
+                                                        ));
 
        shared_ptr<libdcp::SoundAsset> ms (new libdcp::SoundAsset (
                                                  sigc::ptr_fun (&wav),
@@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE (error_test)
        vector<string> p;
        p.push_back ("frobozz");
 
-       BOOST_CHECK_THROW (new libdcp::PictureAsset (p, "build/test/bar", "video.mxf", &d.Progress, 24, 24, 32, 32), libdcp::FileError);
+       BOOST_CHECK_THROW (new libdcp::MonoPictureAsset (p, "build/test/bar", "video.mxf", &d.Progress, 24, 24, 32, 32), libdcp::FileError);
        BOOST_CHECK_THROW (new libdcp::SoundAsset (p, "build/test/bar", "audio.mxf", &d.Progress, 24, 24), libdcp::FileError);
 }