Add interface to set up still image lengths.
authorCarl Hetherington <cth@carlh.net>
Sat, 6 Apr 2013 11:26:12 +0000 (12:26 +0100)
committerCarl Hetherington <cth@carlh.net>
Sat, 6 Apr 2013 11:26:12 +0000 (12:26 +0100)
18 files changed:
src/lib/content.cc
src/lib/content.h
src/lib/ffmpeg_content.cc
src/lib/ffmpeg_content.h
src/lib/film.cc
src/lib/film.h
src/lib/imagemagick_content.cc
src/lib/imagemagick_content.h
src/lib/player.cc
src/lib/player.h
src/lib/playlist.cc
src/lib/playlist.h
src/lib/sndfile_content.h
src/lib/video_content.cc
src/wx/film_editor.cc
src/wx/film_editor.h
src/wx/film_viewer.cc
src/wx/film_viewer.h

index 786b5fb09be505bcf0bcd56765c41a30b45d0b17..9c3bcd39dcf6cd5585c20d7e9d70a4d8f52cb9c9 100644 (file)
@@ -39,7 +39,8 @@ Content::Content (shared_ptr<const cxml::Node> node)
 }
 
 Content::Content (Content const & o)
-       : _file (o._file)
+       : boost::enable_shared_from_this<Content> (o)
+       , _file (o._file)
        , _digest (o._digest)
 {
 
@@ -60,3 +61,9 @@ Content::examine (shared_ptr<Film>, shared_ptr<Job>, bool)
        boost::mutex::scoped_lock lm (_mutex);
        _digest = d;
 }
+
+void
+Content::signal_changed (int p)
+{
+       Changed (shared_from_this (), p);
+}
index 11c7438a66493ee3f4a79fa8344b2df27bf671df..fc2672c954bbf875761b0e3443dab5fe2c48709d 100644 (file)
@@ -23,6 +23,7 @@
 #include <boost/filesystem.hpp>
 #include <boost/signals2.hpp>
 #include <boost/thread/mutex.hpp>
+#include <boost/enable_shared_from_this.hpp>
 #include <libxml++/libxml++.h>
 
 namespace cxml {
@@ -32,7 +33,7 @@ namespace cxml {
 class Job;
 class Film;
 
-class Content
+class Content : public boost::enable_shared_from_this<Content>
 {
 public:
        Content (boost::filesystem::path);
@@ -50,9 +51,11 @@ public:
                return _file;
        }
 
-       boost::signals2::signal<void (int)> Changed;
+       boost::signals2::signal<void (boost::weak_ptr<Content>, int)> Changed;
 
 protected:
+       void signal_changed (int);
+       
        mutable boost::mutex _mutex;
 
 private:
index 7834cb76e825cc1b6987f469de747d3661029977..cc95105e5cc280afc482f3c607df477c8ceb76dd 100644 (file)
@@ -73,7 +73,6 @@ FFmpegContent::FFmpegContent (FFmpegContent const & o)
        : Content (o)
        , VideoContent (o)
        , AudioContent (o)
-       , boost::enable_shared_from_this<FFmpegContent> (o)
        , _subtitle_streams (o._subtitle_streams)
        , _subtitle_stream (o._subtitle_stream)
        , _audio_streams (o._audio_streams)
@@ -148,11 +147,11 @@ FFmpegContent::examine (shared_ptr<Film> film, shared_ptr<Job> job, bool quick)
 
         take_from_video_decoder (decoder);
 
-        Changed (VideoContentProperty::VIDEO_LENGTH);
-        Changed (FFmpegContentProperty::SUBTITLE_STREAMS);
-        Changed (FFmpegContentProperty::SUBTITLE_STREAM);
-        Changed (FFmpegContentProperty::AUDIO_STREAMS);
-        Changed (FFmpegContentProperty::AUDIO_STREAM);
+        signal_changed (VideoContentProperty::VIDEO_LENGTH);
+        signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
+        signal_changed (FFmpegContentProperty::SUBTITLE_STREAM);
+        signal_changed (FFmpegContentProperty::AUDIO_STREAMS);
+        signal_changed (FFmpegContentProperty::AUDIO_STREAM);
 }
 
 string
@@ -184,7 +183,7 @@ FFmpegContent::set_subtitle_stream (FFmpegSubtitleStream s)
                 _subtitle_stream = s;
         }
 
-        Changed (FFmpegContentProperty::SUBTITLE_STREAM);
+        signal_changed (FFmpegContentProperty::SUBTITLE_STREAM);
 }
 
 void
@@ -195,7 +194,7 @@ FFmpegContent::set_audio_stream (FFmpegAudioStream s)
                 _audio_stream = s;
         }
 
-        Changed (FFmpegContentProperty::AUDIO_STREAM);
+        signal_changed (FFmpegContentProperty::AUDIO_STREAM);
 }
 
 ContentAudioFrame
index 3d69a2f994029f38e935d3c57bfc34ecb7f7e3e6..cc603e680d692855948c3f1bbfa3b6e88b5a6a8f 100644 (file)
@@ -77,12 +77,16 @@ public:
         static int const AUDIO_STREAM;
 };
 
-class FFmpegContent : public VideoContent, public AudioContent, public boost::enable_shared_from_this<FFmpegContent>
+class FFmpegContent : public VideoContent, public AudioContent
 {
 public:
        FFmpegContent (boost::filesystem::path);
        FFmpegContent (boost::shared_ptr<const cxml::Node>);
        FFmpegContent (FFmpegContent const &);
+
+       boost::shared_ptr<FFmpegContent> shared_from_this () {
+               return boost::dynamic_pointer_cast<FFmpegContent> (Content::shared_from_this ());
+       }
        
        void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
        std::string summary () const;
index 976f653137d1ddb41e5a3abb7d17573b3ca1322d..69d2a28e20afc30f2fe63c6c6f4c9ad92389e0e3 100644 (file)
@@ -110,6 +110,8 @@ Film::Film (string d, bool must_exist)
        , _dirty (false)
 {
        set_dci_date_today ();
+
+       _playlist->ContentChanged.connect (bind (&Film::content_changed, this, _1, _2));
        
        /* Make state.directory a complete path without ..s (where possible)
           (Code swiped from Adam Bowen on stackoverflow)
@@ -179,6 +181,8 @@ Film::Film (Film const & o)
                _content.push_back ((*i)->clone ());
        }
        
+       _playlist->ContentChanged.connect (bind (&Film::content_changed, this, _1, _2));
+       
        _playlist->setup (_content);
 }
 
@@ -485,14 +489,17 @@ Film::read_metadata ()
        for (list<shared_ptr<cxml::Node> >::iterator i = c.begin(); i != c.end(); ++i) {
 
                string const type = (*i)->string_child ("Type");
+               boost::shared_ptr<Content> c;
                
                if (type == "FFmpeg") {
-                       _content.push_back (shared_ptr<Content> (new FFmpegContent (*i)));
+                       c.reset (new FFmpegContent (*i));
                } else if (type == "ImageMagick") {
-                       _content.push_back (shared_ptr<Content> (new ImageMagickContent (*i)));
+                       c.reset (new ImageMagickContent (*i));
                } else if (type == "Sndfile") {
-                       _content.push_back (shared_ptr<Content> (new SndfileContent (*i)));
+                       c.reset (new SndfileContent (*i));
                }
+
+               _content.push_back (c);
        }
 
        _dirty = false;
@@ -1037,7 +1044,6 @@ Film::add_content (shared_ptr<Content> c)
        {
                boost::mutex::scoped_lock lm (_state_mutex);
                _content.push_back (c);
-               _content_connections.push_back (c->Changed.connect (bind (&Film::content_changed, this, _1)));
        }
 
        signal_changed (CONTENT);
@@ -1054,14 +1060,6 @@ Film::remove_content (shared_ptr<Content> c)
                if (i != _content.end ()) {
                        _content.erase (i);
                }
-
-               for (list<boost::signals2::connection>::iterator i = _content_connections.begin(); i != _content_connections.end(); ++i) {
-                       i->disconnect ();
-               }
-
-               for (ContentList::iterator i = _content.begin(); i != _content.end(); ++i) {
-                       _content_connections.push_back (c->Changed.connect (bind (&Film::content_changed, this, _1)));
-               }
        }
 
        signal_changed (CONTENT);
@@ -1238,13 +1236,13 @@ Film::set_ffmpeg_audio_stream (FFmpegAudioStream s)
 }
 
 void
-Film::content_changed (int p)
+Film::content_changed (boost::weak_ptr<Content> c, int p)
 {
        if (p == VideoContentProperty::VIDEO_FRAME_RATE) {
                set_dcp_frame_rate (best_dcp_frame_rate (video_frame_rate ()));
        }
 
        if (ui_signaller) {
-               ui_signaller->emit (boost::bind (boost::ref (ContentChanged), p));
+               ui_signaller->emit (boost::bind (boost::ref (ContentChanged), c, p));
        }
 }
index 091ac4f97bc41a2f4b8fbc91a7f6f44e741a769c..9c5f561e65775b978b431bf2541ba8efd546cdb2 100644 (file)
@@ -119,7 +119,7 @@ public:
 
        void set_ffmpeg_subtitle_stream (FFmpegSubtitleStream);
        void set_ffmpeg_audio_stream (FFmpegAudioStream);
-       
+
        /** Identifiers for the parts of our state;
            used for signalling changes.
        */
@@ -299,7 +299,7 @@ public:
        mutable boost::signals2::signal<void (Property)> Changed;
 
        /** Emitted when some property of our content has changed */
-       mutable boost::signals2::signal<void (int)> ContentChanged;
+       mutable boost::signals2::signal<void (boost::weak_ptr<Content>, int)> ContentChanged;
 
        boost::signals2::signal<void ()> AudioAnalysisSucceeded;
 
@@ -312,7 +312,7 @@ private:
        void analyse_audio_finished ();
        std::string video_state_identifier () const;
        void read_metadata ();
-       void content_changed (int);
+       void content_changed (boost::weak_ptr<Content>, int);
        boost::shared_ptr<FFmpegContent> ffmpeg () const;
 
        /** Log to write to */
@@ -334,7 +334,6 @@ private:
        bool _use_dci_name;
        bool _trust_content_headers;
        ContentList _content;
-       std::list<boost::signals2::connection> _content_connections;
        /** The type of content that this Film represents (feature, trailer etc.) */
        DCPContentType const * _dcp_content_type;
        /** The format to present this Film in (flat, scope, etc.) */
index f7c76a34d4a202b04f8f62cf70a73c0c0eac6ba7..912c180a8286f37f959ee53e33dc517edbdb3f1f 100644 (file)
@@ -72,13 +72,13 @@ ImageMagickContent::examine (shared_ptr<Film> film, shared_ptr<Job> job, bool qu
 
        {
                boost::mutex::scoped_lock lm (_mutex);
-               /* XXX */
+               /* Initial length */
                _video_length = 10 * 24;
        }
        
        take_from_video_decoder (decoder);
        
-        Changed (VideoContentProperty::VIDEO_LENGTH);
+        signal_changed (VideoContentProperty::VIDEO_LENGTH);
 }
 
 shared_ptr<Content>
@@ -86,3 +86,14 @@ ImageMagickContent::clone () const
 {
        return shared_ptr<Content> (new ImageMagickContent (*this));
 }
+
+void
+ImageMagickContent::set_video_length (ContentVideoFrame len)
+{
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+               _video_length = len;
+       }
+
+       signal_changed (VideoContentProperty::VIDEO_LENGTH);
+}
index 2ca58f25532866d460f6c96058673cebd24a688e..b1e7f949530a0b70182019639807b58d396b2aaa 100644 (file)
@@ -24,16 +24,22 @@ namespace cxml {
        class Node;
 }
 
-class ImageMagickContent : public VideoContent, public boost::enable_shared_from_this<ImageMagickContent>
+class ImageMagickContent : public VideoContent
 {
 public:
        ImageMagickContent (boost::filesystem::path);
        ImageMagickContent (boost::shared_ptr<const cxml::Node>);
 
+       boost::shared_ptr<ImageMagickContent> shared_from_this () {
+               return boost::dynamic_pointer_cast<ImageMagickContent> (Content::shared_from_this ());
+       };
+
        void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
        std::string summary () const;
        void as_xml (xmlpp::Node *) const;
        boost::shared_ptr<Content> clone () const;
 
+       void set_video_length (ContentVideoFrame);
+
        static bool valid_file (boost::filesystem::path);
 };
index 6e2e7ed140bd00415d432ee53ce7e21e540b8a2d..60917ba0949a6bc272fa20d7e321db7d866e1355 100644 (file)
@@ -27,6 +27,8 @@
 
 using std::list;
 using boost::shared_ptr;
+using boost::weak_ptr;
+using boost::dynamic_pointer_cast;
 
 Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
        : _film (f)
@@ -34,11 +36,12 @@ Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
        , _video (true)
        , _audio (true)
        , _subtitles (true)
-       , _have_setup_decoders (false)
+       , _have_valid_decoders (false)
        , _ffmpeg_decoder_done (false)
        , _video_sync (true)
 {
-
+       _playlist->Changed.connect (bind (&Player::playlist_changed, this));
+       _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2));
 }
 
 void
@@ -62,9 +65,9 @@ Player::disable_subtitles ()
 bool
 Player::pass ()
 {
-       if (!_have_setup_decoders) {
+       if (!_have_valid_decoders) {
                setup_decoders ();
-               _have_setup_decoders = true;
+               _have_valid_decoders = true;
        }
        
        bool done = true;
@@ -138,9 +141,9 @@ Player::process_audio (shared_ptr<AudioBuffers> b)
 bool
 Player::seek (double t)
 {
-       if (!_have_setup_decoders) {
+       if (!_have_valid_decoders) {
                setup_decoders ();
-               _have_setup_decoders = true;
+               _have_valid_decoders = true;
        }
        
        bool r = false;
@@ -183,9 +186,9 @@ Player::seek (double t)
 bool
 Player::seek_to_last ()
 {
-       if (!_have_setup_decoders) {
+       if (!_have_valid_decoders) {
                setup_decoders ();
-               _have_setup_decoders = true;
+               _have_valid_decoders = true;
        }
 
        bool r = false;
@@ -278,3 +281,24 @@ Player::last_video_time () const
 
        return 0;
 }
+
+void
+Player::content_changed (weak_ptr<Content> w, int p)
+{
+       shared_ptr<Content> c = w.lock ();
+       if (!c) {
+               return;
+       }
+
+       if (p == VideoContentProperty::VIDEO_LENGTH) {
+               if (dynamic_pointer_cast<FFmpegContent> (c)) {
+                       _have_valid_decoders = false;
+               }
+       }
+}
+
+void
+Player::playlist_changed ()
+{
+       _have_valid_decoders = false;
+}
index bc728d8f2bde37a4243576e7420830bd9cf872d9..79203692e963dc9c53df06dab626ad798378f6ce 100644 (file)
@@ -56,6 +56,8 @@ private:
        void process_video (boost::shared_ptr<Image> i, bool same, boost::shared_ptr<Subtitle> s);
        void process_audio (boost::shared_ptr<AudioBuffers>);
        void setup_decoders ();
+       void playlist_changed ();
+       void content_changed (boost::weak_ptr<Content>, int);
 
        boost::shared_ptr<const Film> _film;
        boost::shared_ptr<const Playlist> _playlist;
@@ -64,7 +66,7 @@ private:
        bool _audio;
        bool _subtitles;
        
-       bool _have_setup_decoders;
+       bool _have_valid_decoders;
        boost::shared_ptr<FFmpegDecoder> _ffmpeg_decoder;
        bool _ffmpeg_decoder_done;
        std::list<boost::shared_ptr<ImageMagickDecoder> > _imagemagick_decoders;
index 0a4803f6e225404c4ae8998131672b357fde46a4..e0220ef6f6377768852a80ec0e60a489586b28c3 100644 (file)
@@ -31,6 +31,7 @@ using std::list;
 using std::cout;
 using std::vector;
 using boost::shared_ptr;
+using boost::weak_ptr;
 using boost::dynamic_pointer_cast;
 
 Playlist::Playlist ()
@@ -50,6 +51,12 @@ Playlist::setup (ContentList content)
        _imagemagick.clear ();
        _sndfile.clear ();
 
+       for (list<boost::signals2::connection>::iterator i = _content_connections.begin(); i != _content_connections.end(); ++i) {
+               i->disconnect ();
+       }
+       
+       _content_connections.clear ();
+
        for (ContentList::const_iterator i = content.begin(); i != content.end(); ++i) {
                shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (*i);
                if (fc) {
@@ -74,7 +81,11 @@ Playlist::setup (ContentList content)
                        _sndfile.push_back (sc);
                        _audio_from = AUDIO_SNDFILE;
                }
+
+               _content_connections.push_back ((*i)->Changed.connect (bind (&Playlist::content_changed, this, _1, _2)));
        }
+
+       Changed ();
 }
 
 ContentAudioFrame
@@ -208,3 +219,8 @@ Playlist::has_audio () const
        return _audio_from != AUDIO_NONE;
 }
 
+void
+Playlist::content_changed (weak_ptr<Content> c, int p)
+{
+       ContentChanged (c, p);
+}
index 29a52d4339576e3eb2892759c20380cf9dcdb8f3..1a24a02277bc1bd3bb3caf5dff55e3f3e54110e4 100644 (file)
@@ -84,12 +84,19 @@ public:
        std::list<boost::shared_ptr<const SndfileContent> > sndfile () const {
                return _sndfile;
        }
+
+       mutable boost::signals2::signal<void ()> Changed;
+       mutable boost::signals2::signal<void (boost::weak_ptr<Content>, int)> ContentChanged;
        
 private:
+       void content_changed (boost::weak_ptr<Content>, int);
+       
        VideoFrom _video_from;
        AudioFrom _audio_from;
 
        boost::shared_ptr<const FFmpegContent> _ffmpeg;
        std::list<boost::shared_ptr<const ImageMagickContent> > _imagemagick;
        std::list<boost::shared_ptr<const SndfileContent> > _sndfile;
+
+       std::list<boost::signals2::connection> _content_connections;
 };
index 90845ba08d544158e1b6093fd43c900ee97b4ae3..b696b57a54b9c98be0605e8fd004bd33e994d6df 100644 (file)
@@ -28,6 +28,10 @@ class SndfileContent : public AudioContent
 public:
        SndfileContent (boost::filesystem::path);
        SndfileContent (boost::shared_ptr<const cxml::Node>);
+
+       boost::shared_ptr<SndfileContent> shared_from_this () {
+               return boost::dynamic_pointer_cast<SndfileContent> (Content::shared_from_this ());
+       }
        
        std::string summary () const;
        std::string information () const;
index 14897c5706a68852873abe090ef617d39a66f6ce..8176c5c41710c75140f483fa9eed213197c2b921 100644 (file)
@@ -81,14 +81,18 @@ VideoContent::take_from_video_decoder (shared_ptr<VideoDecoder> d)
                _video_frame_rate = vfr;
         }
         
-        Changed (VideoContentProperty::VIDEO_SIZE);
-        Changed (VideoContentProperty::VIDEO_FRAME_RATE);
+        signal_changed (VideoContentProperty::VIDEO_SIZE);
+        signal_changed (VideoContentProperty::VIDEO_FRAME_RATE);
 }
 
 
 string
 VideoContent::information () const
 {
+       if (video_size().width == 0 || video_size().height == 0) {
+               return "";
+       }
+       
        stringstream s;
 
        s << String::compose (
index efbf212d037bbbc6dd08a445319d1f66a2c97d0e..58fc077a357680573ed29235751dd72a0cda87ae 100644 (file)
@@ -59,13 +59,13 @@ using std::setprecision;
 using std::list;
 using std::vector;
 using boost::shared_ptr;
+using boost::weak_ptr;
 using boost::dynamic_pointer_cast;
 using boost::lexical_cast;
 
 /** @param f Film to edit */
 FilmEditor::FilmEditor (shared_ptr<Film> f, wxWindow* parent)
        : wxPanel (parent)
-       , _film (f)
        , _generally_sensitive (true)
        , _audio_dialog (0)
 {
@@ -84,7 +84,7 @@ FilmEditor::FilmEditor (shared_ptr<Film> f, wxWindow* parent)
        make_subtitle_panel ();
        _notebook->AddPage (_subtitle_panel, _("Subtitles"), false);
 
-       set_film (_film);
+       set_film (f);
        connect_to_widgets ();
 
        JobManager::instance()->ActiveJobsChanged.connect (
@@ -200,6 +200,7 @@ FilmEditor::connect_to_widgets ()
        _content_remove->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_remove_clicked), 0, this);
        _content_earlier->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_earlier_clicked), 0, this);
        _content_later->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_later_clicked), 0, this);
+       _imagemagick_video_length->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::imagemagick_video_length_changed), 0, this);
        _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this);
        _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this);
        _top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::top_crop_changed), 0, this);
@@ -354,6 +355,21 @@ FilmEditor::make_content_panel ()
 
        _content_information = new wxTextCtrl (_content_panel, wxID_ANY, wxT ("\n\n\n\n"), wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxTE_MULTILINE);
        _content_sizer->Add (_content_information, 1, wxEXPAND | wxALL, 6);
+
+       wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4);
+       _content_sizer->Add (grid, 0, wxEXPAND | wxALL, 6);
+
+       {
+               add_label_to_sizer (grid, _content_panel, (_("Duration")));
+               wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+               _imagemagick_video_length = new wxSpinCtrl (_content_panel);
+               s->Add (_imagemagick_video_length);
+               /// TRANSLATORS: this is an abbreviation for seconds, the unit of time
+               add_label_to_sizer (s, _content_panel, _("s"));
+               grid->Add (s);
+       }
+
+       _imagemagick_video_length->SetRange (1, 3600);
 }
 
 void
@@ -690,7 +706,7 @@ FilmEditor::film_changed (Film::Property p)
 }
 
 void
-FilmEditor::film_content_changed (int p)
+FilmEditor::film_content_changed (weak_ptr<Content> content, int property)
 {
        if (!_film) {
                /* We call this method ourselves (as well as using it as a signal handler)
@@ -699,23 +715,31 @@ FilmEditor::film_content_changed (int p)
                return;
        }
                
-       if (p == FFmpegContentProperty::SUBTITLE_STREAMS) {
+       if (property == FFmpegContentProperty::SUBTITLE_STREAMS) {
                setup_subtitle_control_sensitivity ();
                setup_streams ();
-       } else if (p == FFmpegContentProperty::AUDIO_STREAMS) {
+       } else if (property == FFmpegContentProperty::AUDIO_STREAMS) {
                setup_streams ();
                setup_show_audio_sensitivity ();
-       } else if (p == VideoContentProperty::VIDEO_LENGTH) {
+       } else if (property == VideoContentProperty::VIDEO_LENGTH) {
                setup_length ();
-               setup_content_information ();
-       } else if (p == FFmpegContentProperty::AUDIO_STREAM) {
+
+               boost::shared_ptr<Content> c = content.lock ();
+               if (c && c == selected_content()) {
+                       setup_content_information ();
+                       shared_ptr<ImageMagickContent> im = dynamic_pointer_cast<ImageMagickContent> (c);
+                       if (im) {
+                               checked_set (_imagemagick_video_length, im->video_length() / 24);
+                       }
+               }
+       } else if (property == FFmpegContentProperty::AUDIO_STREAM) {
                if (_film->ffmpeg_audio_stream()) {
                        checked_set (_ffmpeg_audio_stream, boost::lexical_cast<string> (_film->ffmpeg_audio_stream()->id));
                }
                setup_dcp_name ();
                setup_audio_details ();
                setup_show_audio_sensitivity ();
-       } else if (p == FFmpegContentProperty::SUBTITLE_STREAM) {
+       } else if (property == FFmpegContentProperty::SUBTITLE_STREAM) {
                if (_film->ffmpeg_subtitle_stream()) {
                        checked_set (_ffmpeg_subtitle_stream, boost::lexical_cast<string> (_film->ffmpeg_subtitle_stream()->id));
                }
@@ -797,13 +821,17 @@ FilmEditor::dcp_content_type_changed (wxCommandEvent &)
 void
 FilmEditor::set_film (shared_ptr<Film> f)
 {
+       if (_film == f) {
+               return;
+       }
+       
        _film = f;
 
        set_things_sensitive (_film != 0);
 
        if (_film) {
                _film->Changed.connect (bind (&FilmEditor::film_changed, this, _1));
-               _film->ContentChanged.connect (bind (&FilmEditor::film_content_changed, this, _1));
+               _film->ContentChanged.connect (bind (&FilmEditor::film_content_changed, this, _1, _2));
        }
 
        if (_film) {
@@ -838,10 +866,10 @@ FilmEditor::set_film (shared_ptr<Film> f)
        film_changed (Film::DCI_METADATA);
        film_changed (Film::DCP_FRAME_RATE);
 
-       film_content_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
-       film_content_changed (FFmpegContentProperty::SUBTITLE_STREAM);
-       film_content_changed (FFmpegContentProperty::AUDIO_STREAMS);
-       film_content_changed (FFmpegContentProperty::AUDIO_STREAM);
+       film_content_changed (boost::shared_ptr<Content> (), FFmpegContentProperty::SUBTITLE_STREAMS);
+       film_content_changed (boost::shared_ptr<Content> (), FFmpegContentProperty::SUBTITLE_STREAM);
+       film_content_changed (boost::shared_ptr<Content> (), FFmpegContentProperty::AUDIO_STREAMS);
+       film_content_changed (boost::shared_ptr<Content> (), FFmpegContentProperty::AUDIO_STREAM);
 }
 
 /** Updates the sensitivity of lots of widgets to a given value.
@@ -1224,40 +1252,28 @@ FilmEditor::content_add_clicked (wxCommandEvent &)
 void
 FilmEditor::content_remove_clicked (wxCommandEvent &)
 {
-       int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
-       if (s == -1) {
-               return;
+       shared_ptr<Content> c = selected_content ();
+       if (c) {
+               _film->remove_content (c);
        }
-
-       ContentList c = _film->content ();
-       assert (s >= 0 && size_t (s) < c.size ());
-       _film->remove_content (c[s]);
 }
 
 void
 FilmEditor::content_earlier_clicked (wxCommandEvent &)
 {
-       int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
-       if (s == -1) {
-               return;
+       shared_ptr<Content> c = selected_content ();
+       if (c) {
+               _film->move_content_earlier (c);
        }
-
-       ContentList c = _film->content ();
-       assert (s >= 0 && size_t (s) < c.size ());
-       _film->move_content_earlier (c[s]);
 }
 
 void
 FilmEditor::content_later_clicked (wxCommandEvent &)
 {
-       int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
-       if (s == -1) {
-               return;
+       shared_ptr<Content> c = selected_content ();
+       if (c) {
+               _film->move_content_later (c);
        }
-
-       ContentList c = _film->content ();
-       assert (s >= 0 && size_t (s) < c.size ());
-       _film->move_content_later (c[s]);
 }
 
 void
@@ -1265,20 +1281,27 @@ FilmEditor::content_item_selected (wxListEvent &)
 {
         setup_content_button_sensitivity ();
        setup_content_information ();
+
+       shared_ptr<Content> c = selected_content ();
+       if (c) {
+               shared_ptr<ImageMagickContent> im = dynamic_pointer_cast<ImageMagickContent> (c);
+               _imagemagick_video_length->Enable (im);
+               if (im) {
+                       checked_set (_imagemagick_video_length, im->video_length() / 24);
+               }
+       }
 }
 
 void
 FilmEditor::setup_content_information ()
 {
-       int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
-       if (s == -1) {
+       shared_ptr<Content> c = selected_content ();
+       if (!c) {
                _content_information->SetValue (wxT (""));
                return;
        }
 
-       ContentList c = _film->content ();
-       assert (s >= 0 && size_t (s) < c.size ());
-       _content_information->SetValue (std_to_wx (c[s]->information ()));
+       _content_information->SetValue (std_to_wx (c->information ()));
 }
 
 void
@@ -1291,3 +1314,32 @@ FilmEditor::setup_content_button_sensitivity ()
         _content_earlier->Enable (have_selection && _generally_sensitive);
         _content_later->Enable (have_selection && _generally_sensitive);
 }
+
+void
+FilmEditor::imagemagick_video_length_changed (wxCommandEvent &)
+{
+       shared_ptr<Content> c = selected_content ();
+       if (!c) {
+               return;
+       }
+
+       shared_ptr<ImageMagickContent> im = dynamic_pointer_cast<ImageMagickContent> (c);
+       if (!im) {
+               return;
+       }
+       
+       im->set_video_length (_imagemagick_video_length->GetValue() * 24);
+}
+
+shared_ptr<Content>
+FilmEditor::selected_content ()
+{
+       int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+       if (s == -1) {
+               return shared_ptr<Content> ();
+       }
+
+       ContentList c = _film->content ();
+       assert (s >= 0 && size_t (s) < c.size ());
+       return c[s];
+}
index 97d1e0dd3dd2b728951d5688788e2ac6278e0965..2870714f92acc813b3b0d210aeff46fdd5dec69f 100644 (file)
@@ -68,6 +68,7 @@ private:
        void content_remove_clicked (wxCommandEvent &);
        void content_earlier_clicked (wxCommandEvent &);
        void content_later_clicked (wxCommandEvent &);
+       void imagemagick_video_length_changed (wxCommandEvent &);
        void format_changed (wxCommandEvent &);
        void trim_start_changed (wxCommandEvent &);
        void trim_end_changed (wxCommandEvent &);
@@ -87,13 +88,11 @@ private:
        void ffmpeg_subtitle_stream_changed (wxCommandEvent &);
        void dcp_frame_rate_changed (wxCommandEvent &);
        void best_dcp_frame_rate_clicked (wxCommandEvent &);
+       void edit_filters_clicked (wxCommandEvent &);
 
        /* Handle changes to the model */
        void film_changed (Film::Property);
-       void film_content_changed (int);
-
-       /* Button clicks */
-       void edit_filters_clicked (wxCommandEvent &);
+       void film_content_changed (boost::weak_ptr<Content>, int);
 
        void set_things_sensitive (bool);
        void setup_formats ();
@@ -109,6 +108,7 @@ private:
        void setup_content_information ();
        
        void active_jobs_changed (bool);
+       boost::shared_ptr<Content> selected_content ();
 
        wxNotebook* _notebook;
        wxPanel* _film_panel;
@@ -134,6 +134,7 @@ private:
        wxButton* _content_earlier;
        wxButton* _content_later;
        wxTextCtrl* _content_information;
+       wxSpinCtrl* _imagemagick_video_length;
        wxButton* _edit_dci_button;
        wxChoice* _format;
        wxStaticText* _format_description;
index 316a42a664cbd025da53084ae8d629c4982bfaea..08358c51943d792a50d62dd7448a1148dba71517 100644 (file)
@@ -37,6 +37,7 @@
 #include "lib/player.h"
 #include "lib/video_content.h"
 #include "lib/ffmpeg_content.h"
+#include "lib/imagemagick_content.h"
 #include "film_viewer.h"
 #include "wx_util.h"
 #include "video_decoder.h"
@@ -47,6 +48,7 @@ using std::max;
 using std::cout;
 using std::list;
 using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
 using libdcp::Size;
 
 FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
@@ -84,6 +86,16 @@ FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
 
        set_film (f);
 
+       _player = _film->player ();
+       _player->disable_audio ();
+       _player->disable_video_sync ();
+
+       /* Don't disable subtitles here as we may need them, and it's nice to be able to turn them
+          on and off without needing obtain a new Player.
+       */
+       
+       _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3));
+
        JobManager::instance()->ActiveJobsChanged.connect (
                bind (&FilmViewer::active_jobs_changed, this, _1)
                );
@@ -99,7 +111,6 @@ FilmViewer::film_changed (Film::Property p)
                break;
        case Film::CONTENT:
        {
-               setup_player ();
                calculate_sizes ();
                get_frame ();
                _panel->Refresh ();
@@ -123,32 +134,6 @@ FilmViewer::film_changed (Film::Property p)
        }
 }
 
-void
-FilmViewer::setup_player ()
-{
-       _player = _film->player ();
-       _player->disable_audio ();
-       _player->disable_video_sync ();
-
-       /* Don't disable subtitles here as we may need them, and it's nice to be able to turn them
-          on and off without needing obtain a new Player.
-       */
-       
-       _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3));
-}
-
-void
-FilmViewer::film_content_changed (int p)
-{
-       if (p == VideoContentProperty::VIDEO_LENGTH || p == VideoContentProperty::VIDEO_SIZE) {
-               setup_player ();
-               calculate_sizes ();
-               get_frame ();
-               _panel->Refresh ();
-               _v_sizer->Layout ();
-       }
-}
-
 void
 FilmViewer::set_film (shared_ptr<Film> f)
 {
@@ -163,14 +148,12 @@ FilmViewer::set_film (shared_ptr<Film> f)
        }
 
        _film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1));
-       _film->ContentChanged.connect (boost::bind (&FilmViewer::film_content_changed, this, _1));
 
        film_changed (Film::CONTENT);
        film_changed (Film::FORMAT);
        film_changed (Film::WITH_SUBTITLES);
        film_changed (Film::SUBTITLE_OFFSET);
        film_changed (Film::SUBTITLE_SCALE);
-       film_content_changed (FFmpegContentProperty::SUBTITLE_STREAM);
 }
 
 void
index bf956ef95d3dc29ce2378d9261aaefbf5ac64f8e..22f44370381836acca1aeb666deb03035ef2cb9a 100644 (file)
@@ -61,7 +61,6 @@ public:
 
 private:
        void film_changed (Film::Property);
-       void film_content_changed (int);
        void paint_panel (wxPaintEvent &);
        void panel_sized (wxSizeEvent &);
        void slider_moved (wxScrollEvent &);
@@ -75,7 +74,6 @@ private:
        void raw_to_display ();
        void get_frame ();
        void active_jobs_changed (bool);
-       void setup_player ();
 
        boost::shared_ptr<Film> _film;
        boost::shared_ptr<Player> _player;