Untested support for splitting into multiple reels. Use J2K bandwidth and colour...
authorCarl Hetherington <cth@carlh.net>
Sat, 12 Jan 2013 21:09:23 +0000 (21:09 +0000)
committerCarl Hetherington <cth@carlh.net>
Sat, 12 Jan 2013 21:09:23 +0000 (21:09 +0000)
ChangeLog
src/lib/film.cc
src/lib/film.h
src/lib/make_dcp_job.cc
src/lib/make_dcp_job.h
src/wx/film_editor.cc
src/wx/film_editor.h
wscript

index f2563ef109b6b45a780effcf6755c5f17b3be3fc..b2d8be18e9bf3abd6e04c9e0d1a9c57eb2196c2c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-01-12  Carl Hetherington  <cth@carlh.net>
+
+       * Untested support for splitting DCPs
+       into multiple reels.
+
 2013-01-09  Carl Hetherington  <cth@carlh.net>
 
        * Try to build with 0.10.4-ish ffmpeg.
index 4e48a0e73f172f4af274b631869d59317ef62f96..3985baf04ff90d4d5b4a42ef180c947861f22b26 100644 (file)
@@ -157,6 +157,7 @@ Film::Film (Film const & o)
        , _scaler            (o._scaler)
        , _dcp_trim_start    (o._dcp_trim_start)
        , _dcp_trim_end      (o._dcp_trim_end)
+       , _reel_size         (o._reel_size)
        , _dcp_ab            (o._dcp_ab)
        , _content_audio_stream (o._content_audio_stream)
        , _external_audio    (o._external_audio)
@@ -216,7 +217,9 @@ Film::j2k_dir () const
          << "_" << content_digest()
          << "_" << crop().left << "_" << crop().right << "_" << crop().top << "_" << crop().bottom
          << "_" << f.first << "_" << f.second
-         << "_" << scaler()->id();
+         << "_" << scaler()->id()
+         << "_" << j2k_bandwidth()
+         << "_" << boost::lexical_cast<int> (colour_lut());
 
        p /= s.str ();
 
@@ -410,6 +413,9 @@ Film::write_metadata () const
        f << "scaler " << _scaler->id () << "\n";
        f << "dcp_trim_start " << _dcp_trim_start << "\n";
        f << "dcp_trim_end " << _dcp_trim_end << "\n";
+       if (_reel_size) {
+               f << "reel_size " << _reel_size.get() << "\n";
+       }
        f << "dcp_ab " << (_dcp_ab ? "1" : "0") << "\n";
        if (_content_audio_stream) {
                f << "selected_content_audio_stream " << _content_audio_stream->to_string() << "\n";
@@ -524,6 +530,8 @@ Film::read_metadata ()
                        _dcp_trim_start = atoi (v.c_str ());
                } else if (k == "dcp_trim_end") {
                        _dcp_trim_end = atoi (v.c_str ());
+               } else if (k == "reel_size") {
+                       _reel_size = boost::lexical_cast<uint64_t> (v);
                } else if (k == "dcp_ab") {
                        _dcp_ab = (v == "1");
                } else if (k == "selected_content_audio_stream" || (!version && k == "selected_audio_stream")) {
@@ -1085,6 +1093,26 @@ Film::set_dcp_trim_end (int t)
        signal_changed (DCP_TRIM_END);
 }
 
+void
+Film::set_reel_size (uint64_t s)
+{
+       {
+               boost::mutex::scoped_lock lm (_state_mutex);
+               _reel_size = s;
+       }
+       signal_changed (REEL_SIZE);
+}
+
+void
+Film::unset_reel_size ()
+{
+       {
+               boost::mutex::scoped_lock lm (_state_mutex);
+               _reel_size = boost::optional<uint64_t> ();
+       }
+       signal_changed (REEL_SIZE);
+}
+
 void
 Film::set_dcp_ab (bool a)
 {
index 467573ae12f03cb10ef09cf82422268d3a8c80cc..02d9cf7d076949225f52e25d179234f70e688bd3 100644 (file)
@@ -113,6 +113,7 @@ public:
                SCALER,
                DCP_TRIM_START,
                DCP_TRIM_END,
+               REEL_SIZE,
                DCP_AB,
                CONTENT_AUDIO_STREAM,
                EXTERNAL_AUDIO,
@@ -196,6 +197,11 @@ public:
                boost::mutex::scoped_lock lm (_state_mutex);
                return _dcp_trim_end;
        }
+
+       boost::optional<uint64_t> reel_size () const {
+               boost::mutex::scoped_lock lm (_state_mutex);
+               return _reel_size;
+       }
        
        bool dcp_ab () const {
                boost::mutex::scoped_lock lm (_state_mutex);
@@ -357,6 +363,8 @@ public:
        void set_scaler (Scaler const *);
        void set_dcp_trim_start (int);
        void set_dcp_trim_end (int);
+       void set_reel_size (uint64_t);
+       void unset_reel_size ();
        void set_dcp_ab (bool);
        void set_content_audio_stream (boost::shared_ptr<AudioStream>);
        void set_external_audio (std::vector<std::string>);
@@ -435,6 +443,8 @@ private:
        int _dcp_trim_start;
        /** Frames to trim off the end of the DCP */
        int _dcp_trim_end;
+       /** Approximate target reel size in bytes; if not set, use a single reel */
+       boost::optional<uint64_t> _reel_size;
        /** true to create an A/B comparison DCP, where the left half of the image
            is the video without any filters or post-processing, and the right half
            has the specified filters and post-processing.
index 5272d6badf59b341d8ed1d2a851b207ab03d9806..34b3e5124ee60b315e893df6e1a9a0a289934700 100644 (file)
@@ -37,6 +37,7 @@ extern "C" {
 #include "film.h"
 
 using std::string;
+using std::cout;
 using boost::shared_ptr;
 
 /** @param f Film we are making the DCP for.
@@ -57,9 +58,9 @@ MakeDCPJob::name () const
 
 /** @param f DCP frame index */
 string
-MakeDCPJob::j2c_path (int f) const
+MakeDCPJob::j2c_path (int f, int offset) const
 {
-       SourceFrame const s = (f * dcp_frame_rate(_film->frames_per_second()).skip) + _film->dcp_trim_start();
+       SourceFrame const s = ((f + offset) * dcp_frame_rate(_film->frames_per_second()).skip) + _film->dcp_trim_start();
        return _opt->frame_out_path (s, false);
 }
 
@@ -75,6 +76,8 @@ MakeDCPJob::run ()
        if (!_film->dcp_length()) {
                throw EncodeError ("cannot make a DCP when the source length is not known");
        }
+
+       descend (0.9);
        
        string const dcp_path = _film->dir (_film->dcp_name());
 
@@ -103,45 +106,74 @@ MakeDCPJob::run ()
        
        dcp.add_cpl (cpl);
 
-       descend (0.8);
-       shared_ptr<libdcp::MonoPictureAsset> pa (
-               new libdcp::MonoPictureAsset (
-                       boost::bind (&MakeDCPJob::j2c_path, this, _1),
-                       _film->dir (_film->dcp_name()),
-                       "video.mxf",
-                       &dcp.Progress,
-                       dfr.frames_per_second,
-                       frames,
-                       _opt->out_size.width,
-                       _opt->out_size.height
-                       )
-               );
-       
-       ascend ();
+       int frames_per_reel = 0;
+       if (_film->reel_size()) {
+               frames_per_reel = (_film->reel_size().get() / (_film->j2k_bandwidth() / 8)) * dfr.frames_per_second;
+       } else {
+               frames_per_reel = frames;
+       }
 
-       shared_ptr<libdcp::SoundAsset> sa;
+       int frames_done = 0;
+       int reel = 0;
 
-       if (_film->audio_channels() > 0) {
-               descend (0.1);
-               sa.reset (
-                       new libdcp::SoundAsset (
-                               boost::bind (&MakeDCPJob::wav_path, this, _1),
+       while (frames_done < frames) {
+
+               descend (float (frames_per_reel) / frames);
+
+               int this_time = std::min (frames_per_reel, (frames - frames_done));
+
+               descend (0.8);
+
+               shared_ptr<libdcp::MonoPictureAsset> pa (
+                       new libdcp::MonoPictureAsset (
+                               boost::bind (&MakeDCPJob::j2c_path, this, _1, frames_done),
                                _film->dir (_film->dcp_name()),
-                               "audio.mxf",
+                               String::compose ("video_%1.mxf", reel),
                                &dcp.Progress,
                                dfr.frames_per_second,
-                               frames,
-                               dcp_audio_channels (_film->audio_channels())
+                               this_time,
+                               _opt->out_size.width,
+                               _opt->out_size.height
                                )
                        );
+       
+               ascend ();
+               
+               shared_ptr<libdcp::SoundAsset> sa;
+               
+               if (_film->audio_channels() > 0) {
+                       descend (0.1);
+                       sa.reset (
+                               new libdcp::SoundAsset (
+                                       boost::bind (&MakeDCPJob::wav_path, this, _1),
+                                       _film->dir (_film->dcp_name()),
+                                       String::compose ("audio_%1.mxf", reel),
+                                       &dcp.Progress,
+                                       dfr.frames_per_second,
+                                       this_time,
+                                       frames_done,
+                                       dcp_audio_channels (_film->audio_channels())
+                                       )
+                               );
+                       ascend ();
+               }
+
+               descend (0.1);
+               cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (pa, sa, shared_ptr<libdcp::SubtitleAsset> ())));
+               ascend ();
+               
+               frames_done += frames_per_reel;
+               ++reel;
+
                ascend ();
        }
 
+       ascend ();
+
        descend (0.1);
-       cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (pa, sa, shared_ptr<libdcp::SubtitleAsset> ())));
        dcp.write_xml ();
        ascend ();
-
+               
        set_progress (1);
        set_state (FINISHED_OK);
 }
index 1aa906b0adc5fd9518334ffab78e47f347d5a37b..5e4f78a2513aa858f8cbe7e851962de2040f19c3 100644 (file)
@@ -38,7 +38,7 @@ public:
 
 private:
        void dcp_progress (float);
-       std::string j2c_path (int) const;
+       std::string j2c_path (int, int) const;
        std::string wav_path (libdcp::Channel) const;
 
        boost::shared_ptr<const EncodeOptions> _opt;
index 72f2d48071316beeec6c7c2a0fc27d7974763642..17c40c83d0eb00ad21bee2c6fe412b1c8ae170d7 100644 (file)
@@ -149,6 +149,17 @@ FilmEditor::make_film_panel ()
                _film_sizer->Add (s);
        }
 
+       _multiple_reels = new wxCheckBox (_film_panel, wxID_ANY, wxT ("Make multiple reels"));
+       _film_sizer->Add (_multiple_reels);
+
+       {
+               wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+               _reel_size = new wxSpinCtrl (_film_panel, wxID_ANY);
+               s->Add (_reel_size);
+               add_label_to_sizer (s, _film_panel, "Gb each");
+               _film_sizer->Add (s);
+       }
+
        _dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, wxT ("A/B"));
        video_control (_dcp_ab);
        _film_sizer->Add (_dcp_ab, 1);
@@ -169,6 +180,8 @@ FilmEditor::make_film_panel ()
        for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
                _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
        }
+
+       _reel_size->SetRange(1, 1000);
 }
 
 void
@@ -191,6 +204,8 @@ FilmEditor::connect_to_widgets ()
        _still_duration->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::still_duration_changed), 0, this);
        _dcp_trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_start_changed), 0, this);
        _dcp_trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_end_changed), 0, this);
+       _multiple_reels->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::multiple_reels_toggled), 0, this);
+       _reel_size->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::reel_size_changed), 0, this);
        _with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this);
        _subtitle_offset->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this);
        _subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this);
@@ -463,6 +478,32 @@ FilmEditor::trust_content_header_changed (wxCommandEvent &)
        _film->set_trust_content_header (_trust_content_header->GetValue ());
 }
 
+void
+FilmEditor::multiple_reels_toggled (wxCommandEvent &)
+{
+       if (!_film) {
+               return;
+       }
+
+       if (_multiple_reels->GetValue()) {
+               _film->set_reel_size (_reel_size->GetValue() * 1e9);
+       } else {
+               _film->unset_reel_size ();
+       }
+
+       setup_reel_control_sensitivity ();
+}
+
+void
+FilmEditor::reel_size_changed (wxCommandEvent &)
+{
+       if (!_film) {
+               return;
+       }
+
+       _film->set_reel_size (static_cast<uint64_t> (_reel_size->GetValue()) * 1e9);
+}
+
 /** Called when the DCP A/B switch has been toggled */
 void
 FilmEditor::dcp_ab_toggled (wxCommandEvent &)
@@ -640,6 +681,15 @@ FilmEditor::film_changed (Film::Property p)
        case Film::DCP_TRIM_END:
                checked_set (_dcp_trim_end, _film->dcp_trim_end());
                break;
+       case Film::REEL_SIZE:
+               if (_film->reel_size()) {
+                       checked_set (_multiple_reels, true);
+                       checked_set (_reel_size, _film->reel_size().get() / 1e9);
+               } else {
+                       checked_set (_multiple_reels, false);
+               }
+               setup_reel_control_sensitivity ();
+               break;
        case Film::AUDIO_GAIN:
                checked_set (_audio_gain, _film->audio_gain ());
                break;
@@ -763,6 +813,7 @@ FilmEditor::set_film (shared_ptr<Film> f)
        film_changed (Film::SCALER);
        film_changed (Film::DCP_TRIM_START);
        film_changed (Film::DCP_TRIM_END);
+       film_changed (Film::REEL_SIZE);
        film_changed (Film::DCP_AB);
        film_changed (Film::CONTENT_AUDIO_STREAM);
        film_changed (Film::EXTERNAL_AUDIO);
@@ -807,6 +858,8 @@ FilmEditor::set_things_sensitive (bool s)
        _dcp_content_type->Enable (s);
        _dcp_trim_start->Enable (s);
        _dcp_trim_end->Enable (s);
+       _multiple_reels->Enable (s);
+       _reel_size->Enable (s);
        _dcp_ab->Enable (s);
        _colour_lut->Enable (s);
        _j2k_bandwidth->Enable (s);
@@ -817,6 +870,7 @@ FilmEditor::set_things_sensitive (bool s)
 
        setup_subtitle_control_sensitivity ();
        setup_audio_control_sensitivity ();
+       setup_reel_control_sensitivity ();
 }
 
 /** Called when the `Edit filters' button has been clicked */
@@ -1157,3 +1211,9 @@ FilmEditor::external_audio_changed (wxCommandEvent &)
 
        _film->set_external_audio (a);
 }
+
+void
+FilmEditor::setup_reel_control_sensitivity ()
+{
+       _reel_size->Enable (_multiple_reels->GetValue ());
+}
index 8a900f1e4bedf05bf325183739d96e0b34383ec5..34e67eef13e8a7dc0e41a5d83dbc73806f4a462e 100644 (file)
@@ -65,6 +65,8 @@ private:
        void format_changed (wxCommandEvent &);
        void dcp_trim_start_changed (wxCommandEvent &);
        void dcp_trim_end_changed (wxCommandEvent &);
+       void multiple_reels_toggled (wxCommandEvent &);
+       void reel_size_changed (wxCommandEvent &);
        void dcp_content_type_changed (wxCommandEvent &);
        void dcp_ab_toggled (wxCommandEvent &);
        void scaler_changed (wxCommandEvent &);
@@ -92,6 +94,7 @@ private:
        void setup_formats ();
        void setup_subtitle_control_sensitivity ();
        void setup_audio_control_sensitivity ();
+       void setup_reel_control_sensitivity ();
        void setup_streams ();
        void setup_audio_details ();
        
@@ -167,6 +170,8 @@ private:
 
        wxSpinCtrl* _dcp_trim_start;
        wxSpinCtrl* _dcp_trim_end;
+       wxCheckBox* _multiple_reels;
+       wxSpinCtrl* _reel_size;
        /** Selector to generate an A/B comparison DCP */
        wxCheckBox* _dcp_ab;
 
diff --git a/wscript b/wscript
index 657ddc1fafbe8025b9735f45eae07e8edfbb49e7..bcd2ed693181e0bdb78fb92544afc52e4f2f7b2b 100644 (file)
--- a/wscript
+++ b/wscript
@@ -50,7 +50,7 @@ def configure(conf):
         conf.env.append_value('CXXFLAGS', '-O2')
 
     if not conf.options.static:
-        conf.check_cfg(package = 'libdcp', atleast_version = '0.34', args = '--cflags --libs', uselib_store = 'DCP', mandatory = True)
+        conf.check_cfg(package = 'libdcp', atleast_version = '0.36', args = '--cflags --libs', uselib_store = 'DCP', mandatory = True)
         conf.check_cfg(package = 'libavformat', args = '--cflags --libs', uselib_store = 'AVFORMAT', mandatory = True)
         conf.check_cfg(package = 'libavfilter', args = '--cflags --libs', uselib_store = 'AVFILTER', mandatory = True)
         conf.check_cfg(package = 'libavcodec', args = '--cflags --libs', uselib_store = 'AVCODEC', mandatory = True)