Add basics of colourspace conversion bypass (#266).
authorCarl Hetherington <cth@carlh.net>
Fri, 24 Oct 2014 21:34:45 +0000 (22:34 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 24 Oct 2014 21:34:45 +0000 (22:34 +0100)
ChangeLog
cscript
src/lib/colour_conversion.cc
src/lib/colour_conversion.h
src/lib/dcp_video_frame.cc
src/lib/player_video_frame.cc
src/lib/player_video_frame.h
src/lib/video_content.cc
src/lib/video_content.h
src/wx/video_panel.cc
src/wx/video_panel.h

index 026d30275e347e591a1ebfd1e9328555aea28dfd..31fbbeba5884cf1fd285d715905523fd30f65fc6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2014-10-24  Carl Hetherington  <cth@carlh.net>
 
+       * Experimental support for bypassing colourspace conversion (#266).
+
        * Version 1.76.6 released.
 
 2014-10-23  Carl Hetherington  <cth@carlh.net>
diff --git a/cscript b/cscript
index 495d7723ac090efbf05efad1e956cb87c4410e3b..409b85d1e90acfbad13dd22f6c6258c8aac46d45 100644 (file)
--- a/cscript
+++ b/cscript
@@ -156,7 +156,7 @@ def make_control(debian_version, bits, filename, debug):
 
 def dependencies(target):
     return (('ffmpeg-cdist', '2dffa11'),
-            ('libdcp', 'd5accd6'))
+            ('libdcp', '0073935'))
 
 def build(target, options):
     cmd = './waf configure --prefix=%s' % target.directory
index e5b1104ff9427525dcd374c76d146eedccfb1775..daf890aea0628940104c11e68cc472ff764c0c43 100644 (file)
@@ -84,6 +84,16 @@ ColourConversion::ColourConversion (cxml::NodePtr node)
        output_gamma = node->number_child<double> ("OutputGamma");
 }
 
+boost::optional<ColourConversion>
+ColourConversion::from_xml (cxml::NodePtr node)
+{
+       if (!node->optional_node_child ("InputGamma")) {
+               return boost::optional<ColourConversion> ();
+       }
+
+       return ColourConversion (node);
+}
+
 void
 ColourConversion::as_xml (xmlpp::Node* node) const
 {
index fa1a955e1e414806fe84453657e3b09c6c49a03b..706e51fe8cd60ef1f731024d179989f922d5cd19 100644 (file)
@@ -46,6 +46,8 @@ public:
 
        boost::optional<size_t> preset () const;
 
+       static boost::optional<ColourConversion> from_xml (cxml::NodePtr);
+
        double input_gamma;
        bool input_gamma_linearised;
        boost::numeric::ublas::matrix<double> matrix;
index fac247aeb6a67e552e76239c1e302f445be97080..e3a9fcc11f7e9713e7501c363e555d2cd55a37bf 100644 (file)
@@ -108,29 +108,36 @@ DCPVideoFrame::DCPVideoFrame (shared_ptr<const PlayerVideoFrame> frame, shared_p
 shared_ptr<EncodedData>
 DCPVideoFrame::encode_locally ()
 {
-       shared_ptr<libdcp::LUT> in_lut;
-       if (_frame->colour_conversion().input_gamma_linearised) {
-               in_lut = libdcp::SRGBLinearisedGammaLUT::cache.get (12, _frame->colour_conversion().input_gamma);
-       } else {
-               in_lut = libdcp::GammaLUT::cache.get (12, _frame->colour_conversion().input_gamma);
-       }
-
-       /* XXX: libdcp should probably use boost */
-       
-       double matrix[3][3];
-       for (int i = 0; i < 3; ++i) {
-               for (int j = 0; j < 3; ++j) {
-                       matrix[i][j] = _frame->colour_conversion().matrix (i, j);
+       shared_ptr<libdcp::XYZFrame> xyz;
+
+       if (_frame->colour_conversion()) {
+               ColourConversion conversion = _frame->colour_conversion().get ();
+               shared_ptr<libdcp::LUT> in_lut;
+               if (conversion.input_gamma_linearised) {
+                       in_lut = libdcp::SRGBLinearisedGammaLUT::cache.get (12, conversion.input_gamma);
+               } else {
+                       in_lut = libdcp::GammaLUT::cache.get (12, conversion.input_gamma);
+               }
+               
+               /* XXX: libdcp should probably use boost */
+               
+               double matrix[3][3];
+               for (int i = 0; i < 3; ++i) {
+                       for (int j = 0; j < 3; ++j) {
+                               matrix[i][j] = conversion.matrix (i, j);
+                       }
                }
+               
+               xyz = libdcp::rgb_to_xyz (
+                       _frame->image(AV_PIX_FMT_RGB48LE),
+                       in_lut,
+                       libdcp::GammaLUT::cache.get (16, 1 / conversion.output_gamma),
+                       matrix
+                       );
+       } else {
+               xyz = libdcp::xyz_to_xyz (_frame->image (AV_PIX_FMT_RGB48LE));
        }
 
-       shared_ptr<libdcp::XYZFrame> xyz = libdcp::rgb_to_xyz (
-               _frame->image(AV_PIX_FMT_RGB48LE),
-               in_lut,
-               libdcp::GammaLUT::cache.get (16, 1 / _frame->colour_conversion().output_gamma),
-               matrix
-               );
-
        /* Set the max image and component sizes based on frame_rate */
        int max_cs_len = ((float) _j2k_bandwidth) / 8 / _frames_per_second;
        if (_frame->eyes() == EYES_LEFT || _frame->eyes() == EYES_RIGHT) {
index 63ddc637b2fd60eb9ebac578479cbc83b8c1572f..771e0a912e2a2977b438732e5e53aaf4116d23ed 100644 (file)
@@ -36,7 +36,7 @@ PlayerVideoFrame::PlayerVideoFrame (
        Scaler const * scaler,
        Eyes eyes,
        Part part,
-       ColourConversion colour_conversion
+       boost::optional<ColourConversion> colour_conversion
        )
        : _in (in)
        , _crop (crop)
@@ -59,7 +59,7 @@ PlayerVideoFrame::PlayerVideoFrame (shared_ptr<cxml::Node> node, shared_ptr<Sock
        _scaler = Scaler::from_id (node->string_child ("Scaler"));
        _eyes = (Eyes) node->number_child<int> ("Eyes");
        _part = (Part) node->number_child<int> ("Part");
-       _colour_conversion = ColourConversion (node);
+       _colour_conversion = ColourConversion::from_xml (node);
 
        _in = image_proxy_factory (node->node_child ("In"), socket, log);
 
@@ -129,7 +129,9 @@ PlayerVideoFrame::add_metadata (xmlpp::Node* node) const
        node->add_child("Scaler")->add_child_text (_scaler->id ());
        node->add_child("Eyes")->add_child_text (raw_convert<string> (_eyes));
        node->add_child("Part")->add_child_text (raw_convert<string> (_part));
-       _colour_conversion.as_xml (node);
+       if (_colour_conversion) {
+               _colour_conversion.get().as_xml (node);
+       }
        if (_subtitle_image) {
                node->add_child ("SubtitleWidth")->add_child_text (raw_convert<string> (_subtitle_image->size().width));
                node->add_child ("SubtitleHeight")->add_child_text (raw_convert<string> (_subtitle_image->size().height));
index 6a6868292076b8e83ebaac110b46c1b763ccdbf4..6b123c6e1850f398fe5f41c5ba282bcca9ff6cd5 100644 (file)
@@ -38,7 +38,7 @@ class Log;
 class PlayerVideoFrame
 {
 public:
-       PlayerVideoFrame (boost::shared_ptr<const ImageProxy>, Crop, libdcp::Size, libdcp::Size, Scaler const *, Eyes, Part, ColourConversion);
+       PlayerVideoFrame (boost::shared_ptr<const ImageProxy>, Crop, libdcp::Size, libdcp::Size, Scaler const *, Eyes, Part, boost::optional<ColourConversion>);
        PlayerVideoFrame (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>, boost::shared_ptr<Log>);
 
        void set_subtitle (boost::shared_ptr<const Image>, Position<int>);
@@ -52,7 +52,7 @@ public:
                return _eyes;
        }
 
-       ColourConversion colour_conversion () const {
+       boost::optional<ColourConversion> colour_conversion () const {
                return _colour_conversion;
        }
 
@@ -64,7 +64,7 @@ private:
        Scaler const * _scaler;
        Eyes _eyes;
        Part _part;
-       ColourConversion _colour_conversion;
+       boost::optional<ColourConversion> _colour_conversion;
        boost::shared_ptr<const Image> _subtitle_image;
        Position<int> _subtitle_position;
 };
index 13f2cf51676a9d10bb3b6acce245457d1dd2db66..3094a70c8ca34a87c01f13c82400cf46702ce139 100644 (file)
@@ -61,7 +61,7 @@ VideoContent::VideoContent (shared_ptr<const Film> f)
        , _video_frame_type (VIDEO_FRAME_TYPE_2D)
        , _scale (Config::instance()->default_scale ())
 {
-       setup_default_colour_conversion ();
+       set_default_colour_conversion ();
 }
 
 VideoContent::VideoContent (shared_ptr<const Film> f, Time s, VideoContent::Frame len)
@@ -72,7 +72,7 @@ VideoContent::VideoContent (shared_ptr<const Film> f, Time s, VideoContent::Fram
        , _video_frame_type (VIDEO_FRAME_TYPE_2D)
        , _scale (Config::instance()->default_scale ())
 {
-       setup_default_colour_conversion ();
+       set_default_colour_conversion ();
 }
 
 VideoContent::VideoContent (shared_ptr<const Film> f, boost::filesystem::path p)
@@ -83,7 +83,7 @@ VideoContent::VideoContent (shared_ptr<const Film> f, boost::filesystem::path p)
        , _video_frame_type (VIDEO_FRAME_TYPE_2D)
        , _scale (Config::instance()->default_scale ())
 {
-       setup_default_colour_conversion ();
+       set_default_colour_conversion ();
 }
 
 VideoContent::VideoContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int version)
@@ -108,8 +108,10 @@ VideoContent::VideoContent (shared_ptr<const Film> f, shared_ptr<const cxml::Nod
        } else {
                _scale = VideoContentScale (node->node_child ("Scale"));
        }
-       
-       _colour_conversion = ColourConversion (node->node_child ("ColourConversion"));
+
+       if (node->optional_node_child ("ColourConversion")) {
+               _colour_conversion = ColourConversion (node->node_child ("ColourConversion"));
+       }
 }
 
 VideoContent::VideoContent (shared_ptr<const Film> f, vector<shared_ptr<Content> > c)
@@ -170,13 +172,15 @@ VideoContent::as_xml (xmlpp::Node* node) const
        node->add_child("VideoFrameType")->add_child_text (raw_convert<string> (static_cast<int> (_video_frame_type)));
        _crop.as_xml (node);
        _scale.as_xml (node->add_child("Scale"));
-       _colour_conversion.as_xml (node->add_child("ColourConversion"));
+       if (_colour_conversion) {
+               _colour_conversion.get().as_xml (node->add_child("ColourConversion"));
+       }
 }
 
 void
-VideoContent::setup_default_colour_conversion ()
+VideoContent::set_default_colour_conversion ()
 {
-       _colour_conversion = PresetColourConversion (_("sRGB"), 2.4, true, libdcp::colour_matrix::srgb_to_xyz, 2.6).conversion;
+       set_colour_conversion (PresetColourConversion (_("sRGB"), 2.4, true, libdcp::colour_matrix::srgb_to_xyz, 2.6).conversion);
 }
 
 void
@@ -303,8 +307,11 @@ VideoContent::identifier () const
          << "_" << crop().right
          << "_" << crop().top
          << "_" << crop().bottom
-         << "_" << scale().id()
-         << "_" << colour_conversion().identifier ();
+         << "_" << scale().id();
+
+       if (colour_conversion()) {
+               s << "_" << colour_conversion().get().identifier ();
+       }
 
        return s.str ();
 }
@@ -348,6 +355,17 @@ VideoContent::video_size_after_3d_split () const
        assert (false);
 }
 
+void
+VideoContent::unset_colour_conversion ()
+{
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+               _colour_conversion = boost::optional<ColourConversion> ();
+       }
+
+       signal_changed (VideoContentProperty::COLOUR_CONVERSION);
+}
+
 void
 VideoContent::set_colour_conversion (ColourConversion c)
 {
index 3a7b44306ca80890b10deca55c496127860ff352..9aa3be521e48f8ee0187ce2907007c1fa4cb3fd6 100644 (file)
@@ -92,7 +92,9 @@ public:
        void set_bottom_crop (int);
 
        void set_scale (VideoContentScale);
+       void unset_colour_conversion ();
        void set_colour_conversion (ColourConversion);
+       void set_default_colour_conversion ();
        
        VideoFrameType video_frame_type () const {
                boost::mutex::scoped_lock lm (_mutex);
@@ -130,7 +132,7 @@ public:
                return _scale;
        }
 
-       ColourConversion colour_conversion () const {
+       boost::optional<ColourConversion> colour_conversion () const {
                boost::mutex::scoped_lock lm (_mutex);
                return _colour_conversion;
        }
@@ -156,13 +158,11 @@ private:
        friend class best_dcp_frame_rate_test_double;
        friend class audio_sampling_rate_test;
 
-       void setup_default_colour_conversion ();
-       
        libdcp::Size _video_size;
        VideoFrameType _video_frame_type;
        Crop _crop;
        VideoContentScale _scale;
-       ColourConversion _colour_conversion;
+       boost::optional<ColourConversion> _colour_conversion;
 };
 
 #endif
index b33a97591c6617e45fe3a2da2a04bd1fca0fbe24..eb0b812a5dd194c99130b206650e51bcc51bc399 100644 (file)
@@ -147,7 +147,7 @@ VideoPanel::VideoPanel (FilmEditor* e)
                wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
 
                wxClientDC dc (this);
-               wxSize size = dc.GetTextExtent (wxT ("A quite long name"));
+               wxSize size = dc.GetTextExtent (wxT ("A quite long-ish name"));
                size.SetHeight (-1);
                
                _filters = new wxStaticText (this, wxID_ANY, _("None"), wxDefaultPosition, size);
@@ -159,11 +159,13 @@ VideoPanel::VideoPanel (FilmEditor* e)
        ++r;
        
        {
-               add_label_to_grid_bag_sizer (grid, this, _("Colour conversion"), true, wxGBPosition (r, 0));
+               _enable_colour_conversion = new wxCheckBox (this, wxID_ANY, _("Colour conversion"));
+               grid->Add (_enable_colour_conversion, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+
                wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
 
                wxClientDC dc (this);
-               wxSize size = dc.GetTextExtent (wxT ("A quite long name"));
+               wxSize size = dc.GetTextExtent (wxT ("A quite long-ish name"));
                size.SetHeight (-1);
                
                _colour_conversion = new wxStaticText (this, wxID_ANY, wxT (""), wxDefaultPosition, size);
@@ -202,6 +204,7 @@ VideoPanel::VideoPanel (FilmEditor* e)
        _frame_type->wrapped()->Append (_("3D right only"));
 
        _filters_button->Bind           (wxEVT_COMMAND_BUTTON_CLICKED,   boost::bind (&VideoPanel::edit_filters_clicked, this));
+       _enable_colour_conversion->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&VideoPanel::enable_colour_conversion_clicked, this));
        _colour_conversion_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED,   boost::bind (&VideoPanel::edit_colour_conversion_clicked, this));
 }
 
@@ -239,9 +242,21 @@ VideoPanel::film_content_changed (int property)
        } else if (property == VideoContentProperty::VIDEO_FRAME_RATE) {
                setup_description ();
        } else if (property == VideoContentProperty::COLOUR_CONVERSION) {
-               optional<size_t> preset = vcs ? vcs->colour_conversion().preset () : optional<size_t> ();
-               vector<PresetColourConversion> cc = Config::instance()->colour_conversions ();
-               _colour_conversion->SetLabel (preset ? std_to_wx (cc[preset.get()].name) : _("Custom"));
+               if (!vcs) {
+                       _colour_conversion->SetLabel (wxT (""));
+               } else if (vcs->colour_conversion ()) {
+                       optional<size_t> preset = vcs->colour_conversion().get().preset ();
+                       vector<PresetColourConversion> cc = Config::instance()->colour_conversions ();
+                       _colour_conversion->SetLabel (preset ? std_to_wx (cc[preset.get()].name) : _("Custom"));
+                       _enable_colour_conversion->SetValue (true);
+                       _colour_conversion->Enable (true);
+                       _colour_conversion_button->Enable (true);
+               } else {
+                       _colour_conversion->SetLabel (_("None"));
+                       _enable_colour_conversion->SetValue (false);
+                       _colour_conversion->Enable (false);
+                       _colour_conversion_button->Enable (false);
+               }
        } else if (property == FFmpegContentProperty::FILTERS) {
                if (fcs) {
                        string const p = Filter::ffmpeg_string (fcs->filters ());
@@ -351,7 +366,11 @@ VideoPanel::edit_colour_conversion_clicked ()
                return;
        }
 
-       ColourConversion conversion = vc.front()->colour_conversion ();
+       if (!vc.front()->colour_conversion ()) {
+               return;
+       }
+
+       ColourConversion conversion = vc.front()->colour_conversion().get ();
        ContentColourConversionDialog* d = new ContentColourConversionDialog (this);
        d->set (conversion);
        d->ShowModal ();
@@ -383,3 +402,18 @@ VideoPanel::content_selection_changed ()
        film_content_changed (VideoContentProperty::COLOUR_CONVERSION);
        film_content_changed (FFmpegContentProperty::FILTERS);
 }
+
+void
+VideoPanel::enable_colour_conversion_clicked ()
+{
+       VideoContentList vc = _editor->selected_video_content ();
+       if (vc.size() != 1) {
+               return;
+       }
+
+       if (_enable_colour_conversion->GetValue()) {
+               vc.front()->set_default_colour_conversion ();
+       } else {
+               vc.front()->unset_colour_conversion ();
+       }
+}
index 99633491d835ea9948538ad696459035e5f16876..16ecb7e2ed6ecec629d65f7d471b38a4bdc51d4c 100644 (file)
@@ -37,6 +37,7 @@ public:
 
 private:
        void edit_filters_clicked ();
+       void enable_colour_conversion_clicked ();
        void edit_colour_conversion_clicked ();
 
        void setup_description ();
@@ -50,6 +51,7 @@ private:
        wxStaticText* _description;
        wxStaticText* _filters;
        wxButton* _filters_button;
+       wxCheckBox* _enable_colour_conversion;
        wxStaticText* _colour_conversion;
        wxButton* _colour_conversion_button;
 };