Merge ImageMagick and FFmpeg content into VideoContent list; remove seek_to_last...
authorCarl Hetherington <cth@carlh.net>
Tue, 9 Apr 2013 22:43:00 +0000 (23:43 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 9 Apr 2013 22:43:00 +0000 (23:43 +0100)
17 files changed:
run/dvdomatic
src/lib/decoder.cc
src/lib/decoder.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/film.cc
src/lib/imagemagick_content.cc
src/lib/imagemagick_decoder.cc
src/lib/imagemagick_decoder.h
src/lib/player.cc
src/lib/player.h
src/lib/playlist.cc
src/lib/playlist.h
src/lib/video_decoder.cc
src/lib/video_decoder.h
src/tools/dvdomatic.cc
src/wx/film_viewer.cc

index 147c001cdf3c8fc8e4be4fe0ff8f8f2b0d65e35f..dbc63d44a0d1d5db9eb9ada88cc95fd6e16f5687 100755 (executable)
@@ -3,7 +3,7 @@
 export LD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:$LD_LIBRARY_PATH
 if [ "$1" == "--debug" ]; then
     shift
-    gdb --args build/src/tools/dvdomatic "$*"
+    gdb --args build/src/tools/dvdomatic $*
 elif [ "$1" == "--valgrind" ]; then
     shift
     valgrind --tool="memcheck" build/src/tools/dvdomatic $*
@@ -11,5 +11,5 @@ elif [ "$1" == "--i18n" ]; then
     shift
     LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 build/src/tools/dvdomatic "$*"
 else
-    build/src/tools/dvdomatic "$*"
+    build/src/tools/dvdomatic $*
 fi
index c4044691943334d2cefb575b50f5a23e6716fb5c..082ad5076cd402647f43800596f45614319616f6 100644 (file)
@@ -41,7 +41,7 @@ Decoder::Decoder (shared_ptr<const Film> f)
        _film_connection = f->Changed.connect (bind (&Decoder::film_changed, this, _1));
 }
 
-/** Seek to a position as a source timestamp in seconds.
+/** Seek to a position as a content timestamp in seconds.
  *  @return true on error.
  */
 bool
@@ -49,12 +49,3 @@ Decoder::seek (double)
 {
        throw DecodeError (N_("decoder does not support seek"));
 }
-
-/** Seek so that the next frame we will produce is the same as the last one.
- *  @return true on error.
- */
-bool
-Decoder::seek_to_last ()
-{
-       throw DecodeError (N_("decoder does not support seek"));
-}
index 34accf6c740afdd60eb0e97a1a2e763d28a2c7e8..0fffef25739ca0c6afb9b049b2de7978bbd55a56 100644 (file)
@@ -56,7 +56,6 @@ public:
 
        virtual bool pass () = 0;
        virtual bool seek (double);
-       virtual bool seek_to_last ();
 
 protected:
        boost::shared_ptr<const Film> _film;
index a0949f635ffeb420a3096dfb2e740d6ef98ddaff..d0b1de748c0e2960dc4bc3ed9aeade1c8db2ab00 100644 (file)
@@ -518,22 +518,12 @@ FFmpegDecoder::filter_and_emit_video (AVFrame* frame)
 bool
 FFmpegDecoder::seek (double p)
 {
-       return do_seek (p, false);
-}
-
-bool
-FFmpegDecoder::seek_to_last ()
-{
-       /* This AVSEEK_FLAG_BACKWARD in do_seek is a bit of a hack; without it, if we ask for a seek to the same place as last time
+       /* This use of AVSEEK_FLAG_BACKWARD is a bit of a hack; without it, if we ask for a seek to the same place as last time
           (used when we change decoder parameters and want to re-fetch the frame) we end up going forwards rather than
           staying in the same place.
        */
-       return do_seek (last_source_time(), true);
-}
-
-bool
-FFmpegDecoder::do_seek (double p, bool backwards)
-{
+       bool const backwards = (p == last_content_time());
+       
        int64_t const vt = p / av_q2d (_format_context->streams[_video_stream]->time_base);
 
        int const r = av_seek_frame (_format_context, _video_stream, vt, backwards ? AVSEEK_FLAG_BACKWARD : 0);
index cd37d20c6de6cabc53545690a060bedc71720fee..f6a53874ae723871d4d6dba390d57dccab047597 100644 (file)
@@ -77,7 +77,6 @@ public:
        }
 
        bool seek (double);
-       bool seek_to_last ();
        bool pass ();
 
 private:
@@ -86,7 +85,6 @@ private:
        FFmpegDecoder (FFmpegDecoder const &);
        FFmpegDecoder& operator= (FFmpegDecoder const &);
 
-       bool do_seek (double p, bool);
        PixelFormat pixel_format () const;
        AVSampleFormat audio_sample_format () const;
        int bytes_per_audio_sample () const;
index b36dc8f9c0f5dac258533e9879f5103add8bb232..35a07b399e3432716f61f64e7d892abf98f056de 100644 (file)
@@ -69,6 +69,7 @@ using std::setfill;
 using std::min;
 using std::make_pair;
 using std::endl;
+using std::cout;
 using std::list;
 using boost::shared_ptr;
 using boost::lexical_cast;
@@ -1084,7 +1085,6 @@ Film::move_content_earlier (shared_ptr<Content> c)
                --j;
 
                swap (*i, *j);
-               _playlist->setup (_content);
        }
 
        signal_changed (CONTENT);
@@ -1107,7 +1107,6 @@ Film::move_content_later (shared_ptr<Content> c)
                }
 
                swap (*i, *j);
-               _playlist->setup (_content);
        }
 
        signal_changed (CONTENT);
index 59fde40bb7d1059025bdaa91f941485c2204e2c5..24f6d338d4a8d3d75d06daebb07945c45f736f6f 100644 (file)
@@ -32,7 +32,7 @@ ImageMagickContent::ImageMagickContent (boost::filesystem::path f)
        : Content (f)
        , VideoContent (f)
 {
-       
+
 }
 
 ImageMagickContent::ImageMagickContent (shared_ptr<const cxml::Node> node)
index 6a2be1a7ca720560666d955da64eb5651c7eeef2..7049b7d6e31945ace55eadd9e16bc4ef6f04a170 100644 (file)
@@ -105,16 +105,6 @@ ImageMagickDecoder::pixel_format () const
        return PIX_FMT_RGB24;
 }
 
-bool
-ImageMagickDecoder::seek_to_last ()
-{
-       if (_position > 0) {
-               --_position;
-       }
-
-       return false;
-}
-
 bool
 ImageMagickDecoder::seek (double t)
 {
index cb524b44ba2bad08b9fabcde78f7a815d72ccfa3..52c7bec186495cdbe4026e7bce1d325d3d6a8211 100644 (file)
@@ -50,7 +50,6 @@ public:
        }
 
        bool seek (double);
-       bool seek_to_last ();
        bool pass ();
 
 protected:
index 756c3b85493bf940b8c15f136b7194907fb965d5..19899f6daabe92f404c6148bde4da6633ce37c91 100644 (file)
@@ -20,7 +20,9 @@
 #include "player.h"
 #include "film.h"
 #include "ffmpeg_decoder.h"
+#include "ffmpeg_content.h"
 #include "imagemagick_decoder.h"
+#include "imagemagick_content.h"
 #include "sndfile_decoder.h"
 #include "sndfile_content.h"
 #include "playlist.h"
@@ -39,7 +41,6 @@ Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
        , _audio (true)
        , _subtitles (true)
        , _have_valid_decoders (false)
-       , _ffmpeg_decoder_done (false)
        , _video_sync (true)
 {
        _playlist->Changed.connect (bind (&Player::playlist_changed, this));
@@ -74,25 +75,13 @@ Player::pass ()
        
        bool done = true;
        
-       if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
-               if (!_ffmpeg_decoder_done) {
-                       if (_ffmpeg_decoder->pass ()) {
-                               _ffmpeg_decoder_done = true;
-                       } else {
-                               done = false;
-                       }
+       if (_video_decoder != _video_decoders.end ()) {
+               if ((*_video_decoder)->pass ()) {
+                       _video_decoder++;
                }
-       }
-
-       if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) {
-               if (_imagemagick_decoder != _imagemagick_decoders.end ()) {
-                       if ((*_imagemagick_decoder)->pass ()) {
-                               _imagemagick_decoder++;
-                       }
-
-                       if (_imagemagick_decoder != _imagemagick_decoders.end ()) {
-                               done = false;
-                       }
+               
+               if (_video_decoder != _video_decoders.end ()) {
+                       done = false;
                }
        }
 
@@ -114,26 +103,18 @@ void
 Player::set_progress (shared_ptr<Job> job)
 {
        /* Assume progress can be divined from how far through the video we are */
-       switch (_playlist->video_from ()) {
-       case Playlist::VIDEO_NONE:
-               break;
-       case Playlist::VIDEO_FFMPEG:
-               if (_playlist->video_length ()) {
-                       job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ());
-               }
-               break;
-       case Playlist::VIDEO_IMAGEMAGICK:
-       {
-               int n = 0;
-               for (list<shared_ptr<ImageMagickDecoder> >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) {
-                       if (_imagemagick_decoder == i) {
-                               job->set_progress (float (n) / _imagemagick_decoders.size ());
-                       }
-                       ++n;
-               }
-               break;
+
+       if (_video_decoder == _video_decoders.end() || !_playlist->video_length()) {
+               return;
        }
+       
+       ContentVideoFrame p = 0;
+       list<shared_ptr<VideoDecoder> >::iterator i = _video_decoders.begin ();
+       while (i != _video_decoders.end() && i != _video_decoder) {
+               p += (*i)->video_length ();
        }
+
+       job->set_progress (float ((*_video_decoder)->video_frame ()) / _playlist->video_length ());
 }
 
 void
@@ -173,109 +154,67 @@ Player::seek (double t)
                _have_valid_decoders = true;
        }
        
-       bool r = false;
-
-       switch (_playlist->video_from()) {
-       case Playlist::VIDEO_NONE:
-               break;
-       case Playlist::VIDEO_FFMPEG:
-               if (!_ffmpeg_decoder || _ffmpeg_decoder->seek (t)) {
-                       r = true;
-               }
-               /* We're seeking, so all `all done' bets are off */
-               _ffmpeg_decoder_done = false;
-               break;
-       case Playlist::VIDEO_IMAGEMAGICK:
-               /* Find the decoder that contains this position */
-               _imagemagick_decoder = _imagemagick_decoders.begin ();
-               while (_imagemagick_decoder != _imagemagick_decoders.end ()) {
-                       double const this_length = (*_imagemagick_decoder)->video_length() / _film->video_frame_rate ();
-                       if (t < this_length) {
-                               break;
-                       }
-                       t -= this_length;
-                       ++_imagemagick_decoder;
+       /* Find the decoder that contains this position */
+       _video_decoder = _video_decoders.begin ();
+       while (_video_decoder != _video_decoders.end ()) {
+               double const this_length = (*_video_decoder)->video_length() / _film->video_frame_rate ();
+               if (t < this_length) {
+                       break;
                }
-
-               if (_imagemagick_decoder != _imagemagick_decoders.end()) {
-                       (*_imagemagick_decoder)->seek (t);
-               } else {
-                       r = true;
-               }
-               break;
-       }
-
-       /* XXX: don't seek audio because we don't need to... */
-
-       return r;
-}
-
-bool
-Player::seek_to_last ()
-{
-       if (!_have_valid_decoders) {
-               setup_decoders ();
-               _have_valid_decoders = true;
+               t -= this_length;
+               ++_video_decoder;
        }
-
-       bool r = false;
        
-       switch (_playlist->video_from ()) {
-       case Playlist::VIDEO_NONE:
-               break;
-       case Playlist::VIDEO_FFMPEG:
-               if (!_ffmpeg_decoder || _ffmpeg_decoder->seek_to_last ()) {
-                       r = true;
-               }
-
-               /* We're seeking, so all `all done' bets are off */
-               _ffmpeg_decoder_done = false;
-               break;
-       case Playlist::VIDEO_IMAGEMAGICK:
-               if ((*_imagemagick_decoder)->seek_to_last ()) {
-                       r = true;
-               }
-               break;
+       if (_video_decoder != _video_decoders.end()) {
+               (*_video_decoder)->seek (t);
+       } else {
+               return true;
        }
 
        /* XXX: don't seek audio because we don't need to... */
 
-       return r;
+       return false;
 }
 
 void
 Player::setup_decoders ()
 {
-       if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) {
-               _ffmpeg_decoder.reset (
-                       new FFmpegDecoder (
-                               _film,
-                               _playlist->ffmpeg(),
-                               _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG,
-                               _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG,
-                               _subtitles && _film->with_subtitles(),
-                               _video_sync
-                               )
-                       );
-       }
-       
-       if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) {
-               _ffmpeg_decoder->connect_video (shared_from_this ());
-       }
+       if (_video) {
+               list<shared_ptr<const VideoContent> > vc = _playlist->video ();
+               for (list<shared_ptr<const VideoContent> >::iterator i = vc.begin(); i != vc.end(); ++i) {
+
+                       shared_ptr<VideoDecoder> d;
+                       
+                       /* XXX: into content? */
+                       
+                       shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
+                       if (fc) {
+                               shared_ptr<FFmpegDecoder> fd (
+                                       new FFmpegDecoder (
+                                               _film, fc, _video,
+                                               _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG,
+                                               _subtitles && _film->with_subtitles(),
+                                               _video_sync
+                                               )
+                                       );
+
+                               if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
+                                       fd->Audio.connect (bind (&Player::process_audio, this, fc, _1));
+                               }
+
+                               d = fd;
+                       }
 
-       if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) {
-               _ffmpeg_decoder->Audio.connect (bind (&Player::process_audio, this, _playlist->ffmpeg (), _1));
-       }
+                       shared_ptr<const ImageMagickContent> ic = dynamic_pointer_cast<const ImageMagickContent> (*i);
+                       if (ic) {
+                               d.reset (new ImageMagickDecoder (_film, ic));
+                       }
 
-       if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) {
-               list<shared_ptr<const ImageMagickContent> > ic = _playlist->imagemagick ();
-               for (list<shared_ptr<const ImageMagickContent> >::iterator i = ic.begin(); i != ic.end(); ++i) {
-                       shared_ptr<ImageMagickDecoder> d (new ImageMagickDecoder (_film, *i));
-                       _imagemagick_decoders.push_back (d);
                        d->connect_video (shared_from_this ());
+                       _video_decoders.push_back (d);
                }
 
-               _imagemagick_decoder = _imagemagick_decoders.begin ();
+               _video_decoder = _video_decoders.begin ();
        }
 
        if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) {
@@ -297,23 +236,12 @@ Player::disable_video_sync ()
 double
 Player::last_video_time () const
 {
-       switch (_playlist->video_from ()) {
-       case Playlist::VIDEO_NONE:
-               return 0;
-       case Playlist::VIDEO_FFMPEG:
-               return _ffmpeg_decoder->last_source_time ();
-       case Playlist::VIDEO_IMAGEMAGICK:
-       {
-               double t = 0;
-               for (list<shared_ptr<ImageMagickDecoder> >::const_iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoder; ++i) {
-                       t += (*i)->video_length() / (*i)->video_frame_rate ();
-               }
-
-               return t + (*_imagemagick_decoder)->last_source_time ();
-       }
+       double t = 0;
+       for (list<shared_ptr<VideoDecoder> >::const_iterator i = _video_decoders.begin(); i != _video_decoder; ++i) {
+               t += (*i)->video_length() / (*i)->video_frame_rate ();
        }
 
-       return 0;
+       return t + (*_video_decoder)->last_content_time ();
 }
 
 void
@@ -326,6 +254,7 @@ Player::content_changed (weak_ptr<Content> w, int p)
 
        if (p == VideoContentProperty::VIDEO_LENGTH) {
                if (dynamic_pointer_cast<FFmpegContent> (c)) {
+                       /* FFmpeg content length changes are serious; we need new decoders */
                        _have_valid_decoders = false;
                }
        }
index afc856316cf48bee32cb4d560fe26dfba4432e4c..8a82ab2980b644e408d35b48f37f0921f2d5e749 100644 (file)
@@ -28,8 +28,7 @@
 #include "video_sink.h"
 #include "audio_sink.h"
 
-class FFmpegDecoder;
-class ImageMagickDecoder;
+class VideoDecoder;
 class SndfileDecoder;
 class Job;
 class Film;
@@ -49,7 +48,6 @@ public:
        bool pass ();
        void set_progress (boost::shared_ptr<Job>);
        bool seek (double);
-       bool seek_to_last ();
 
        double last_video_time () const;
 
@@ -68,10 +66,8 @@ private:
        bool _subtitles;
        
        bool _have_valid_decoders;
-       boost::shared_ptr<FFmpegDecoder> _ffmpeg_decoder;
-       bool _ffmpeg_decoder_done;
-       std::list<boost::shared_ptr<ImageMagickDecoder> > _imagemagick_decoders;
-       std::list<boost::shared_ptr<ImageMagickDecoder> >::iterator _imagemagick_decoder;
+       std::list<boost::shared_ptr<VideoDecoder> > _video_decoders;
+       std::list<boost::shared_ptr<VideoDecoder> >::iterator _video_decoder;
        std::list<boost::shared_ptr<SndfileDecoder> > _sndfile_decoders;
 
        boost::shared_ptr<AudioBuffers> _sndfile_buffers;
index 3f7905fa9c11c251bacdeeefb38f565aab699141..d26dae7309fde44175437aa59a1d0512feb4fd72 100644 (file)
@@ -21,9 +21,9 @@
 #include "playlist.h"
 #include "sndfile_content.h"
 #include "sndfile_decoder.h"
-#include "ffmpeg_content.h"
+#include "video_content.h"
 #include "ffmpeg_decoder.h"
-#include "imagemagick_content.h"
+#include "ffmpeg_content.h"
 #include "imagemagick_decoder.h"
 #include "job.h"
 
@@ -31,13 +31,13 @@ using std::list;
 using std::cout;
 using std::vector;
 using std::min;
+using std::max;
 using boost::shared_ptr;
 using boost::weak_ptr;
 using boost::dynamic_pointer_cast;
 
 Playlist::Playlist ()
-       : _video_from (VIDEO_NONE)
-       , _audio_from (AUDIO_NONE)
+       : _audio_from (AUDIO_FFMPEG)
 {
 
 }
@@ -45,11 +45,9 @@ Playlist::Playlist ()
 void
 Playlist::setup (ContentList content)
 {
-       _video_from = VIDEO_NONE;
-       _audio_from = AUDIO_NONE;
+       _audio_from = AUDIO_FFMPEG;
 
-       _ffmpeg.reset ();
-       _imagemagick.clear ();
+       _video.clear ();
        _sndfile.clear ();
 
        for (list<boost::signals2::connection>::iterator i = _content_connections.begin(); i != _content_connections.end(); ++i) {
@@ -59,24 +57,11 @@ Playlist::setup (ContentList content)
        _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) {
-                       assert (!_ffmpeg);
-                       _ffmpeg = fc;
-                       _video_from = VIDEO_FFMPEG;
-                       if (_audio_from == AUDIO_NONE) {
-                               _audio_from = AUDIO_FFMPEG;
-                       }
+               shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*i);
+               if (vc) {
+                       _video.push_back (vc);
                }
                
-               shared_ptr<ImageMagickContent> ic = dynamic_pointer_cast<ImageMagickContent> (*i);
-               if (ic) {
-                       _imagemagick.push_back (ic);
-                       if (_video_from == VIDEO_NONE) {
-                               _video_from = VIDEO_IMAGEMAGICK;
-                       }
-               }
-
                shared_ptr<SndfileContent> sc = dynamic_pointer_cast<SndfileContent> (*i);
                if (sc) {
                        _sndfile.push_back (sc);
@@ -92,53 +77,65 @@ Playlist::setup (ContentList content)
 ContentAudioFrame
 Playlist::audio_length () const
 {
+       ContentAudioFrame len = 0;
+       
        switch (_audio_from) {
-       case AUDIO_NONE:
-               return 0;
        case AUDIO_FFMPEG:
-               return _ffmpeg->audio_length ();
+               for (list<shared_ptr<const VideoContent> >::const_iterator i = _video.begin(); i != _video.end(); ++i) {
+                       shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
+                       if (fc) {
+                               len += fc->audio_length ();
+                       }
+               }
+               break;
        case AUDIO_SNDFILE:
-       {
-               ContentAudioFrame l = 0;
                for (list<shared_ptr<const SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
-                       l += (*i)->audio_length ();
+                       len += (*i)->audio_length ();
                }
-               return l;
-       }
+               break;
        }
 
-       return 0;
+       return len;
 }
 
 int
 Playlist::audio_channels () const
 {
+       int channels = 0;
+       
        switch (_audio_from) {
-       case AUDIO_NONE:
-               return 0;
        case AUDIO_FFMPEG:
-               return _ffmpeg->audio_channels ();
+               for (list<shared_ptr<const VideoContent> >::const_iterator i = _video.begin(); i != _video.end(); ++i) {
+                       shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
+                       if (fc) {
+                               channels = max (channels, fc->audio_channels ());
+                       }
+               }
+               break;
        case AUDIO_SNDFILE:
-       {
-               int c = 0;
                for (list<shared_ptr<const SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
-                       c += (*i)->audio_channels ();
+                       channels += (*i)->audio_channels ();
                }
-               return c;
-       }
+               break;
        }
 
-       return 0;
+       return channels;
 }
 
 int
 Playlist::audio_frame_rate () const
 {
+       /* XXX: assuming that all content has the same rate */
+       
        switch (_audio_from) {
-       case AUDIO_NONE:
-               return 0;
        case AUDIO_FFMPEG:
-               return _ffmpeg->audio_frame_rate ();
+       {
+               shared_ptr<const FFmpegContent> fc = first_ffmpeg ();
+               if (fc) {
+                       return fc->audio_channels ();
+               }
+               break;
+       }
        case AUDIO_SNDFILE:
                return _sndfile.front()->audio_frame_rate ();
        }
@@ -149,11 +146,17 @@ Playlist::audio_frame_rate () const
 int64_t
 Playlist::audio_channel_layout () const
 {
+       /* XXX: assuming that all content has the same layout */
+
        switch (_audio_from) {
-       case AUDIO_NONE:
-               return 0;
        case AUDIO_FFMPEG:
-               return _ffmpeg->audio_channel_layout ();
+       {
+               shared_ptr<const FFmpegContent> fc = first_ffmpeg ();
+               if (fc) {
+                       return fc->audio_channel_layout ();
+               }
+               break;
+       }
        case AUDIO_SNDFILE:
                /* XXX */
                return 0;
@@ -165,59 +168,41 @@ Playlist::audio_channel_layout () const
 float
 Playlist::video_frame_rate () const
 {
-       switch (_video_from) {
-       case VIDEO_NONE:
+       if (_video.empty ()) {
                return 0;
-       case VIDEO_FFMPEG:
-               return _ffmpeg->video_frame_rate ();
-       case VIDEO_IMAGEMAGICK:
-               return 24;
        }
-
-       return 0;
+       
+       /* XXX: assuming all the same */
+       return _video.front()->video_frame_rate ();
 }
 
 libdcp::Size
 Playlist::video_size () const
 {
-       switch (_video_from) {
-       case VIDEO_NONE:
+       if (_video.empty ()) {
                return libdcp::Size ();
-       case VIDEO_FFMPEG:
-               return _ffmpeg->video_size ();
-       case VIDEO_IMAGEMAGICK:
-               /* XXX */
-               return _imagemagick.front()->video_size ();
        }
 
-       return libdcp::Size ();
+       /* XXX: assuming all the same */
+       return _video.front()->video_size ();
 }
 
 ContentVideoFrame
 Playlist::video_length () const
 {
-       switch (_video_from) {
-       case VIDEO_NONE:
-               return 0;
-       case VIDEO_FFMPEG:
-               return _ffmpeg->video_length ();
-       case VIDEO_IMAGEMAGICK:
-       {
-               ContentVideoFrame l = 0;
-               for (list<shared_ptr<const ImageMagickContent> >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) {
-                       l += (*i)->video_length ();
-               }
-               return l;
+       ContentVideoFrame len = 0;
+       for (list<shared_ptr<const VideoContent> >::const_iterator i = _video.begin(); i != _video.end(); ++i) {
+               len += (*i)->video_length ();
        }
-       }
-
-       return 0;
+       
+       return len;
 }
 
 bool
 Playlist::has_audio () const
 {
-       return _audio_from != AUDIO_NONE;
+       /* XXX */
+       return true;
 }
 
 void
@@ -226,32 +211,51 @@ Playlist::content_changed (weak_ptr<Content> c, int p)
        ContentChanged (c, p);
 }
 
+shared_ptr<const FFmpegContent>
+Playlist::first_ffmpeg () const
+{
+       for (list<shared_ptr<const VideoContent> >::const_iterator i = _video.begin(); i != _video.end(); ++i) {
+               shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (*i);
+               if (fc) {
+                       return fc;
+               }
+       }
+
+       return shared_ptr<const FFmpegContent> ();
+}
+       
+
 AudioMapping
 Playlist::default_audio_mapping () const
 {
        AudioMapping m;
 
        switch (_audio_from) {
-       case AUDIO_NONE:
-               break;
        case AUDIO_FFMPEG:
-               if (_ffmpeg->audio_channels() == 1) {
+       {
+               shared_ptr<const FFmpegContent> fc = first_ffmpeg ();
+               if (!fc) {
+                       break;
+               }
+               
+               /* XXX: assumes all the same */
+               if (fc->audio_channels() == 1) {
                        /* Map mono sources to centre */
-                       m.add (AudioMapping::Channel (_ffmpeg, 0), libdcp::CENTRE);
+                       m.add (AudioMapping::Channel (fc, 0), libdcp::CENTRE);
                } else {
-                       int const N = min (_ffmpeg->audio_channels (), MAX_AUDIO_CHANNELS);
+                       int const N = min (fc->audio_channels (), MAX_AUDIO_CHANNELS);
                        /* Otherwise just start with a 1:1 mapping */
                        for (int i = 0; i < N; ++i) {
-                               m.add (AudioMapping::Channel (_ffmpeg, i), (libdcp::Channel) i);
+                               m.add (AudioMapping::Channel (fc, i), (libdcp::Channel) i);
                        }
                }
                break;
+       }
 
        case AUDIO_SNDFILE:
        {
                int n = 0;
                for (list<shared_ptr<const SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
-                       cout << "sndfile " << (*i)->audio_channels() << "\n";
                        for (int j = 0; j < (*i)->audio_channels(); ++j) {
                                m.add (AudioMapping::Channel (*i, j), (libdcp::Channel) n);
                                ++n;
index 1d189cb070be9077f0ac241fcbefcf190366ac03..4dd27f67538a6c2f38c7b6621184b397b66bfb37 100644 (file)
@@ -56,32 +56,17 @@ public:
 
        AudioMapping default_audio_mapping () const;
 
-       enum VideoFrom {
-               VIDEO_NONE,
-               VIDEO_FFMPEG,
-               VIDEO_IMAGEMAGICK
-       };
-
        enum AudioFrom {
-               AUDIO_NONE,
                AUDIO_FFMPEG,
                AUDIO_SNDFILE
        };
 
-       VideoFrom video_from () const {
-               return _video_from;
-       }
-
        AudioFrom audio_from () const {
                return _audio_from;
        }
 
-       boost::shared_ptr<const FFmpegContent> ffmpeg () const {
-               return _ffmpeg;
-       }
-
-       std::list<boost::shared_ptr<const ImageMagickContent> > imagemagick () const {
-               return _imagemagick;
+       std::list<boost::shared_ptr<const VideoContent> > video () const {
+               return _video;
        }
 
        std::list<boost::shared_ptr<const SndfileContent> > sndfile () const {
@@ -93,12 +78,11 @@ public:
        
 private:
        void content_changed (boost::weak_ptr<Content>, int);
+       boost::shared_ptr<const FFmpegContent> first_ffmpeg () const;
        
-       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 VideoContent> > _video;
        std::list<boost::shared_ptr<const SndfileContent> > _sndfile;
 
        std::list<boost::signals2::connection> _content_connections;
index fd2b28d7f13ed8bee4166491aff55620dc800452..99d711693e44fa942b268375f7f2f6bfda955c3e 100644 (file)
@@ -32,7 +32,7 @@ using boost::optional;
 VideoDecoder::VideoDecoder (shared_ptr<const Film> f)
        : Decoder (f)
        , _video_frame (0)
-       , _last_source_time (0)
+       , _last_content_time (0)
 {
 
 }
@@ -88,7 +88,7 @@ VideoDecoder::signal_video (shared_ptr<Image> image, bool same, shared_ptr<Subti
 
        _last_image = image;
        _last_subtitle = sub;
-       _last_source_time = t;
+       _last_content_time = t;
 }
 
 /** Set up the current subtitle.  This will be put onto frames that
index c04874342c07846f81d69ad9f02797165b3977b3..05cf99a961e3ebbcdda8b97833f0ae5ef5ff48f4 100644 (file)
@@ -48,8 +48,8 @@ public:
                return _video_frame;
        }
 
-       double last_source_time () const {
-               return _last_source_time;
+       double last_content_time () const {
+               return _last_content_time;
        }
 
 protected:
@@ -65,7 +65,7 @@ private:
        void signal_video (boost::shared_ptr<Image>, bool, boost::shared_ptr<Subtitle>, double);
 
        int _video_frame;
-       double _last_source_time;
+       double _last_content_time;
        
        boost::shared_ptr<TimedSubtitle> _timed_subtitle;
 
index 6c27892b0806760a950d5559facbc3e26abe8286..239b4a517ac3d0271d11d5e8ca69a6a2a97a857f 100644 (file)
@@ -59,6 +59,7 @@ static FilmViewer* film_viewer = 0;
 static shared_ptr<Film> film;
 static std::string log_level;
 static std::string film_to_load;
+static std::string film_to_create;
 static wxMenu* jobs_menu = 0;
 static wxLocale* locale = 0;
 
@@ -439,13 +440,15 @@ private:
 #if wxMINOR_VERSION == 9
 static const wxCmdLineEntryDesc command_line_description[] = {
        { wxCMD_LINE_OPTION, "l", "log", "set log level (silent, verbose or timing)", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
-        { wxCMD_LINE_PARAM, 0, 0, "film to load", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
+       { wxCMD_LINE_SWITCH, "n", "new", "create new film", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
+        { wxCMD_LINE_PARAM, 0, 0, "film to load or create", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
        { wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 }
 };
 #else
 static const wxCmdLineEntryDesc command_line_description[] = {
        { wxCMD_LINE_OPTION, wxT("l"), wxT("log"), wxT("set log level (silent, verbose or timing)"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
-        { wxCMD_LINE_PARAM, 0, 0, wxT("film to load"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
+       { wxCMD_LINE_SWITCH, wxT("n"), wxT("new"), wxT("create new film"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
+        { wxCMD_LINE_PARAM, 0, 0, wxT("film to load or create"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
        { wxCMD_LINE_NONE, wxT(""), wxT(""), wxT(""), wxCmdLineParamType (0), 0 }
 };
 #endif
@@ -525,6 +528,12 @@ class App : public wxApp
                        }
                }
 
+               if (!film_to_create.empty ()) {
+                       film.reset (new Film (film_to_create, false));
+                       film->log()->set_level (log_level);
+                       film->set_name (boost::filesystem::path (film_to_create).filename().generic_string ());
+               }
+
                Frame* f = new Frame (_("DVD-o-matic"));
                SetTopWindow (f);
                f->Maximize ();
@@ -545,11 +554,15 @@ class App : public wxApp
        bool OnCmdLineParsed (wxCmdLineParser& parser)
        {
                if (parser.GetParamCount() > 0) {
-                       film_to_load = wx_to_std (parser.GetParam(0));
+                       if (parser.FoundSwitch (wxT ("new"))) {
+                               film_to_create = wx_to_std (parser.GetParam (0));
+                       } else {
+                               film_to_load = wx_to_std (parser.GetParam(0));
+                       }
                }
 
                wxString log;
-               if (parser.Found(wxT("log"), &log)) {
+               if (parser.Found (wxT ("log"), &log)) {
                        log_level = wx_to_std (log);
                }
 
index f8373d3fdc1f31655d9bea599396c24c4c880a1c..8fca8f3709975fdf9cbe7a05a9da47e0e8f0a30b 100644 (file)
@@ -157,7 +157,7 @@ FilmViewer::set_film (shared_ptr<Film> f)
 void
 FilmViewer::update_from_decoder ()
 {
-       if (!_player || _player->seek_to_last ()) {
+       if (!_player || _player->seek (_player->last_video_time ())) {
                return;
        }