Various joining fixes.
authorCarl Hetherington <cth@carlh.net>
Sun, 24 Nov 2013 01:52:23 +0000 (01:52 +0000)
committerCarl Hetherington <cth@carlh.net>
Sun, 24 Nov 2013 01:52:23 +0000 (01:52 +0000)
22 files changed:
src/lib/content.cc
src/lib/content_factory.cc
src/lib/content_factory.h
src/lib/ffmpeg.cc
src/lib/ffmpeg.h
src/lib/ffmpeg_content.cc
src/lib/ffmpeg_content.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_examiner.cc
src/lib/film.cc
src/lib/image_content.cc
src/lib/image_content.h
src/lib/playlist.cc
src/lib/playlist.h
src/lib/sndfile_content.cc
src/lib/sndfile_content.h
src/lib/util.cc
src/lib/video_content.cc
src/tools/dcpomatic.cc
src/wx/film_editor.cc
src/wx/hints_dialog.cc
test/stream_test.cc

index eaa55790ba063eb31bbfc36231f756f2b6ba3054..f09012765a7cbe7616d1e2ae40a870981b74604a 100644 (file)
@@ -25,6 +25,7 @@
 #include "content_factory.h"
 #include "ui_signaller.h"
 #include "exceptions.h"
+#include "film.h"
 
 #include "i18n.h"
 
@@ -102,6 +103,10 @@ Content::Content (shared_ptr<const Film> f, vector<shared_ptr<Content> > c)
                if (i < (c.size() - 1) && c[i]->trim_end ()) {
                        throw JoinError (_("Only the last piece of content to be joined can have an end trim."));
                }
+
+               for (size_t j = 0; j < c[i]->number_of_paths(); ++j) {
+                       _paths.push_back (c[i]->path (j));
+               }
        }
 }
 
@@ -186,7 +191,7 @@ Content::clone () const
        xmlpp::Document doc;
        xmlpp::Node* node = doc.create_root_node ("Content");
        as_xml (node);
-       return content_factory (film, cxml::NodePtr(new cxml::Node (node)));
+       return content_factory (film, cxml::NodePtr (new cxml::Node (node)), Film::state_version);
 }
 
 string
@@ -251,6 +256,8 @@ Content::path_summary () const
 {
        /* XXX: should handle multiple paths more gracefully */
 
+       assert (number_of_paths ());
+
        string s = path(0).filename().string ();
        if (number_of_paths() > 1) {
                s += " ...";
index e800628c161dec79fdb68dc5a4fb8645353ff930..bab22b8eb19e14b6179fd27696710c6b630df70c 100644 (file)
@@ -27,18 +27,18 @@ using std::string;
 using boost::shared_ptr;
 
 shared_ptr<Content>
-content_factory (shared_ptr<const Film> film, cxml::NodePtr node)
+content_factory (shared_ptr<const Film> film, cxml::NodePtr node, int version)
 {
        string const type = node->string_child ("Type");
 
        boost::shared_ptr<Content> content;
        
        if (type == "FFmpeg") {
-               content.reset (new FFmpegContent (film, node));
+               content.reset (new FFmpegContent (film, node, version));
        } else if (type == "Image") {
-               content.reset (new ImageContent (film, node));
+               content.reset (new ImageContent (film, node, version));
        } else if (type == "Sndfile") {
-               content.reset (new SndfileContent (film, node));
+               content.reset (new SndfileContent (film, node, version));
        }
 
        return content;
index d2f75051a2bd0ef2ff47a32c959adc500da93695..071d925e034bbc19309671ede4c07dcd8014dcf0 100644 (file)
@@ -19,5 +19,5 @@
 
 class Film;
 
-extern boost::shared_ptr<Content> content_factory (boost::shared_ptr<const Film>, cxml::NodePtr);
+extern boost::shared_ptr<Content> content_factory (boost::shared_ptr<const Film>, cxml::NodePtr, int);
 extern boost::shared_ptr<Content> content_factory (boost::shared_ptr<const Film>, boost::filesystem::path);
index 3b894a6ff438cd556ddf80128ba0b28a47f1235d..e85a2c44e4912200bf5ebf2013a454b44ddc1e22 100644 (file)
@@ -37,8 +37,7 @@ using boost::lexical_cast;
 
 boost::mutex FFmpeg::_mutex;
 
-/** @param long_probe true to do a long probe of the file looking for streams */
-FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c, bool long_probe)
+FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c)
        : _ffmpeg_content (c)
        , _avio_buffer (0)
        , _avio_buffer_size (4096)
@@ -47,7 +46,7 @@ FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c, bool long_probe)
        , _frame (0)
        , _video_stream (-1)
 {
-       setup_general (long_probe);
+       setup_general ();
        setup_video ();
        setup_audio ();
 }
@@ -81,7 +80,7 @@ avio_seek_wrapper (void* data, int64_t offset, int whence)
 }
 
 void
-FFmpeg::setup_general (bool long_probe)
+FFmpeg::setup_general ()
 {
        av_register_all ();
 
@@ -92,13 +91,11 @@ FFmpeg::setup_general (bool long_probe)
        _format_context->pb = _avio_context;
        
        AVDictionary* options = 0;
-       if (long_probe) {
-               /* These durations are in microseconds, and represent how far into the content file
-                  we will look for streams.
-               */
-               av_dict_set (&options, "analyzeduration", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
-               av_dict_set (&options, "probesize", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
-       }
+       /* These durations are in microseconds, and represent how far into the content file
+          we will look for streams.
+       */
+       av_dict_set (&options, "analyzeduration", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
+       av_dict_set (&options, "probesize", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
        
        if (avformat_open_input (&_format_context, 0, 0, &options) < 0) {
                throw OpenFileError (_ffmpeg_content->path(0).string ());
@@ -176,7 +173,7 @@ FFmpeg::video_codec_context () const
 AVCodecContext *
 FFmpeg::audio_codec_context () const
 {
-       return _format_context->streams[_ffmpeg_content->audio_stream()->id]->codec;
+       return _ffmpeg_content->audio_stream()->stream(_format_context)->codec;
 }
 
 int
index 182ee634b4aadfc6c0e1c5c21f549f9346943c74..760918437d403dd0624984e31a07fb0bdddff583 100644 (file)
@@ -43,7 +43,7 @@ class FFmpegContent;
 class FFmpeg
 {
 public:
-       FFmpeg (boost::shared_ptr<const FFmpegContent>, bool);
+       FFmpeg (boost::shared_ptr<const FFmpegContent>);
        virtual ~FFmpeg ();
 
        boost::shared_ptr<const FFmpegContent> ffmpeg_content () const {
@@ -67,7 +67,8 @@ protected:
        AVFormatContext* _format_context;
        AVPacket _packet;
        AVFrame* _frame;
-       
+
+       /** Index of video stream within AVFormatContext */
        int _video_stream;
 
        /* It would appear (though not completely verified) that one must have
@@ -77,7 +78,7 @@ protected:
        static boost::mutex _mutex;
 
 private:
-       void setup_general (bool);
+       void setup_general ();
        void setup_video ();
        void setup_audio ();
 };
index e843e1e168c3fbb71e561279b9babe2debf6b376..9533315a517e2a0501796bfe3d6f1522f55ff27a 100644 (file)
@@ -17,6 +17,9 @@
 
 */
 
+extern "C" {
+#include <libavformat/avformat.h>
+}
 #include <libcxml/cxml.h>
 #include "ffmpeg_content.h"
 #include "ffmpeg_examiner.h"
@@ -55,7 +58,7 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> f, boost::filesystem::path
 
 }
 
-FFmpegContent::FFmpegContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node)
+FFmpegContent::FFmpegContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int version)
        : Content (f, node)
        , VideoContent (f, node)
        , AudioContent (f, node)
@@ -63,7 +66,7 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> f, shared_ptr<const cxml::N
 {
        list<cxml::NodePtr> c = node->node_children ("SubtitleStream");
        for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) {
-               _subtitle_streams.push_back (shared_ptr<FFmpegSubtitleStream> (new FFmpegSubtitleStream (*i)));
+               _subtitle_streams.push_back (shared_ptr<FFmpegSubtitleStream> (new FFmpegSubtitleStream (*i, version)));
                if ((*i)->optional_number_child<int> ("Selected")) {
                        _subtitle_stream = _subtitle_streams.back ();
                }
@@ -71,7 +74,7 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> f, shared_ptr<const cxml::N
 
        c = node->node_children ("AudioStream");
        for (list<cxml::NodePtr>::const_iterator i = c.begin(); i != c.end(); ++i) {
-               _audio_streams.push_back (shared_ptr<FFmpegAudioStream> (new FFmpegAudioStream (*i)));
+               _audio_streams.push_back (shared_ptr<FFmpegAudioStream> (new FFmpegAudioStream (*i, version)));
                if ((*i)->optional_number_child<int> ("Selected")) {
                        _audio_stream = _audio_streams.back ();
                }
@@ -93,10 +96,10 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> f, vector<boost::shared_ptr
 {
        shared_ptr<FFmpegContent> ref = dynamic_pointer_cast<FFmpegContent> (c[0]);
        assert (ref);
-       
+
        for (size_t i = 0; i < c.size(); ++i) {
                shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c[i]);
-               if (*(fc->_subtitle_stream.get()) != *(ref->_subtitle_stream.get())) {
+               if (f->with_subtitles() && *(fc->_subtitle_stream.get()) != *(ref->_subtitle_stream.get())) {
                        throw JoinError (_("Content to be joined must use the same subtitle stream."));
                }
 
@@ -346,11 +349,33 @@ operator!= (FFmpegAudioStream const & a, FFmpegAudioStream const & b)
        return a.id != b.id;
 }
 
-FFmpegAudioStream::FFmpegAudioStream (shared_ptr<const cxml::Node> node)
-       : mapping (node->node_child ("Mapping"))
+FFmpegStream::FFmpegStream (shared_ptr<const cxml::Node> node, int version)
+       : _legacy_id (false)
 {
        name = node->string_child ("Name");
        id = node->number_child<int> ("Id");
+       if (version == 4 || node->optional_bool_child ("LegacyId")) {
+               _legacy_id = true;
+       }
+}
+
+void
+FFmpegStream::as_xml (xmlpp::Node* root) const
+{
+       root->add_child("Name")->add_child_text (name);
+       root->add_child("Id")->add_child_text (lexical_cast<string> (id));
+       if (_legacy_id) {
+               /* Write this so that version > 4 files are read in correctly
+                  if the Id came originally from a version <= 4 file.
+               */
+               root->add_child("LegacyId")->add_child_text ("1");
+       }
+}
+
+FFmpegAudioStream::FFmpegAudioStream (shared_ptr<const cxml::Node> node, int version)
+       : FFmpegStream (node, version)
+       , mapping (node->node_child ("Mapping"))
+{
        frame_rate = node->number_child<int> ("FrameRate");
        channels = node->number_child<int64_t> ("Channels");
        first_audio = node->optional_number_child<double> ("FirstAudio");
@@ -359,8 +384,7 @@ FFmpegAudioStream::FFmpegAudioStream (shared_ptr<const cxml::Node> node)
 void
 FFmpegAudioStream::as_xml (xmlpp::Node* root) const
 {
-       root->add_child("Name")->add_child_text (name);
-       root->add_child("Id")->add_child_text (lexical_cast<string> (id));
+       FFmpegStream::as_xml (root);
        root->add_child("FrameRate")->add_child_text (lexical_cast<string> (frame_rate));
        root->add_child("Channels")->add_child_text (lexical_cast<string> (channels));
        if (first_audio) {
@@ -369,21 +393,57 @@ FFmpegAudioStream::as_xml (xmlpp::Node* root) const
        mapping.as_xml (root->add_child("Mapping"));
 }
 
+int
+FFmpegStream::index (AVFormatContext const * fc) const
+{
+       if (_legacy_id) {
+               return id;
+       }
+       
+       size_t i = 0;
+       while (i < fc->nb_streams) {
+               if (fc->streams[i]->id == id) {
+                       return i;
+               }
+               ++i;
+       }
+
+       assert (false);
+}
+
+AVStream *
+FFmpegStream::stream (AVFormatContext const * fc) const
+{
+       if (_legacy_id) {
+               return fc->streams[id];
+       }
+       
+       size_t i = 0;
+       while (i < fc->nb_streams) {
+               if (fc->streams[i]->id == id) {
+                       return fc->streams[i];
+               }
+               ++i;
+       }
+
+       assert (false);
+       return 0;
+}
+
 /** Construct a SubtitleStream from a value returned from to_string().
  *  @param t String returned from to_string().
  *  @param v State file version.
  */
-FFmpegSubtitleStream::FFmpegSubtitleStream (shared_ptr<const cxml::Node> node)
+FFmpegSubtitleStream::FFmpegSubtitleStream (shared_ptr<const cxml::Node> node, int version)
+       : FFmpegStream (node, version)
 {
-       name = node->string_child ("Name");
-       id = node->number_child<int> ("Id");
+       
 }
 
 void
 FFmpegSubtitleStream::as_xml (xmlpp::Node* root) const
 {
-       root->add_child("Name")->add_child_text (name);
-       root->add_child("Id")->add_child_text (lexical_cast<string> (id));
+       FFmpegStream::as_xml (root);
 }
 
 Time
index 4576aaf45281f59f50a0743e2983363336acbb4c..7ff159b852b4cb69df4004b1f6a813ad2131e182 100644 (file)
 #include "subtitle_content.h"
 #include "audio_mapping.h"
 
+struct AVFormatContext;
+struct AVStream;
+
 class Filter;
 class ffmpeg_pts_offset_test;
 
-class FFmpegAudioStream
+class FFmpegStream
 {
 public:
-       FFmpegAudioStream (std::string n, int i, int f, int c)
+       FFmpegStream (std::string n, int i)
                : name (n)
                , id (i)
+               , _legacy_id (false)
+       {}
+                               
+       FFmpegStream (boost::shared_ptr<const cxml::Node>, int);
+
+       void as_xml (xmlpp::Node *) const;
+
+       /** @param c An AVFormatContext.
+        *  @return Stream index within the AVFormatContext.
+        */
+       int index (AVFormatContext const * c) const;
+       AVStream* stream (AVFormatContext const * c) const;
+
+       std::string name;
+       int id;
+       
+private:
+       /** If this is true, id is in fact the index */
+       bool _legacy_id;
+};
+
+class FFmpegAudioStream : public FFmpegStream
+{
+public:
+       FFmpegAudioStream (std::string n, int i, int f, int c)
+               : FFmpegStream (n, i)
                , frame_rate (f)
                , channels (c)
                , mapping (c)
@@ -42,12 +71,10 @@ public:
                mapping.make_default ();
        }
 
-       FFmpegAudioStream (boost::shared_ptr<const cxml::Node>);
+       FFmpegAudioStream (boost::shared_ptr<const cxml::Node>, int);
 
        void as_xml (xmlpp::Node *) const;
-       
-       std::string name;
-       int id;
+
        int frame_rate;
        int channels;
        AudioMapping mapping;
@@ -58,27 +85,24 @@ private:
 
        /* Constructor for tests */
        FFmpegAudioStream ()
-               : mapping (1)
+               : FFmpegStream ("", 0)
+               , mapping (1)
        {}
 };
 
 extern bool operator== (FFmpegAudioStream const & a, FFmpegAudioStream const & b);
 extern bool operator!= (FFmpegAudioStream const & a, FFmpegAudioStream const & b);
 
-class FFmpegSubtitleStream
+class FFmpegSubtitleStream : public FFmpegStream
 {
 public:
        FFmpegSubtitleStream (std::string n, int i)
-               : name (n)
-               , id (i)
+               : FFmpegStream (n, i)
        {}
        
-       FFmpegSubtitleStream (boost::shared_ptr<const cxml::Node>);
+       FFmpegSubtitleStream (boost::shared_ptr<const cxml::Node>, int);
 
        void as_xml (xmlpp::Node *) const;
-       
-       std::string name;
-       int id;
 };
 
 extern bool operator== (FFmpegSubtitleStream const & a, FFmpegSubtitleStream const & b);
@@ -98,7 +122,7 @@ class FFmpegContent : public VideoContent, public AudioContent, public SubtitleC
 {
 public:
        FFmpegContent (boost::shared_ptr<const Film>, boost::filesystem::path);
-       FFmpegContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
+       FFmpegContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>, int version);
        FFmpegContent (boost::shared_ptr<const Film>, std::vector<boost::shared_ptr<Content> >);
 
        boost::shared_ptr<FFmpegContent> shared_from_this () {
index be32475377da2c851647bc4ea8f247218c9d24f5..5a1b78762d92e6e30d55108dfae637f8b348e676 100644 (file)
@@ -63,7 +63,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
        , VideoDecoder (f, c)
        , AudioDecoder (f, c)
        , SubtitleDecoder (f)
-       , FFmpeg (c, false)
+       , FFmpeg (c)
        , _subtitle_codec_context (0)
        , _subtitle_codec (0)
        , _decode_video (video)
@@ -171,12 +171,14 @@ FFmpegDecoder::pass ()
 
        shared_ptr<const Film> film = _film.lock ();
        assert (film);
+
+       int const si = _packet.stream_index;
        
-       if (_packet.stream_index == _video_stream && _decode_video) {
+       if (si == _video_stream && _decode_video) {
                decode_video_packet ();
-       } else if (_ffmpeg_content->audio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->id && _decode_audio) {
+       } else if (_ffmpeg_content->audio_stream() && si == _ffmpeg_content->audio_stream()->index (_format_context) && _decode_audio) {
                decode_audio_packet ();
-       } else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id && film->with_subtitles ()) {
+       } else if (_ffmpeg_content->subtitle_stream() && si == _ffmpeg_content->subtitle_stream()->index (_format_context) && film->with_subtitles ()) {
                decode_subtitle_packet ();
        }
 
@@ -511,11 +513,11 @@ FFmpegDecoder::setup_subtitle ()
 {
        boost::mutex::scoped_lock lm (_mutex);
        
-       if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) {
+       if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->index (_format_context) >= int (_format_context->nb_streams)) {
                return;
        }
 
-       _subtitle_codec_context = _format_context->streams[_ffmpeg_content->subtitle_stream()->id]->codec;
+       _subtitle_codec_context = _ffmpeg_content->subtitle_stream()->stream(_format_context)->codec;
        _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id);
 
        if (_subtitle_codec == 0) {
index 8e4f24720bc920204aafcb19a2364ce53034c3d7..78b6e3121c363faf1b0c95a4701970273b970636 100644 (file)
@@ -24,6 +24,8 @@ extern "C" {
 #include "ffmpeg_examiner.h"
 #include "ffmpeg_content.h"
 
+#include "i18n.h"
+
 using std::string;
 using std::cout;
 using std::max;
@@ -32,7 +34,7 @@ using boost::shared_ptr;
 using boost::optional;
 
 FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c)
-       : FFmpeg (c, true)
+       : FFmpeg (c)
 {
        /* Find audio and subtitle streams */
 
@@ -50,12 +52,12 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c)
                        
                        _audio_streams.push_back (
                                shared_ptr<FFmpegAudioStream> (
-                                       new FFmpegAudioStream (audio_stream_name (s), i, s->codec->sample_rate, s->codec->channels)
+                                       new FFmpegAudioStream (audio_stream_name (s), s->id, s->codec->sample_rate, s->codec->channels)
                                        )
                                );
 
                } else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
-                       _subtitle_streams.push_back (shared_ptr<FFmpegSubtitleStream> (new FFmpegSubtitleStream (subtitle_stream_name (s), i)));
+                       _subtitle_streams.push_back (shared_ptr<FFmpegSubtitleStream> (new FFmpegSubtitleStream (subtitle_stream_name (s), s->id)));
                }
        }
 
@@ -78,9 +80,9 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c)
                        }
                } else {
                        for (size_t i = 0; i < _audio_streams.size(); ++i) {
-                               if (_packet.stream_index == _audio_streams[i]->id && !_audio_streams[i]->first_audio) {
+                               if (_packet.stream_index == _audio_streams[i]->index (_format_context) && !_audio_streams[i]->first_audio) {
                                        if (avcodec_decode_audio4 (context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
-                                               _audio_streams[i]->first_audio = frame_time (_audio_streams[i]->id);
+                                               _audio_streams[i]->first_audio = frame_time (_audio_streams[i]->index (_format_context));
                                        }
                                }
                        }
index eab91c7d2b26dc343f8fe7c733cf6a1186ce4fec..d53d61a633217c51e5573cdabfcedf40ab9c7f3f 100644 (file)
@@ -83,7 +83,7 @@ using boost::optional;
 using libdcp::Size;
 using libdcp::Signer;
 
-int const Film::state_version = 4;
+int const Film::state_version = 5;
 
 /** Construct a Film object in a given directory.
  *
@@ -374,6 +374,8 @@ Film::read_metadata ()
 
        cxml::Document f ("Metadata");
        f.read_file (file ("metadata.xml"));
+
+       int const version = f.number_child<int> ("Version");
        
        _name = f.string_child ("Name");
        _use_dci_name = f.bool_child ("UseDCIName");
@@ -405,7 +407,7 @@ Film::read_metadata ()
        _three_d = f.bool_child ("ThreeD");
        _interop = f.bool_child ("Interop");
        _key = libdcp::Key (f.string_child ("Key"));
-       _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"));
+       _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), version);
 
        _dirty = false;
 }
index 14a7c97d5c32511f5f7df2cd8580d86036bf5abf..b05fa6b8d69ce8599503e3d9b3c1e6c5179e6c9a 100644 (file)
@@ -50,7 +50,7 @@ ImageContent::ImageContent (shared_ptr<const Film> f, boost::filesystem::path p)
 }
 
 
-ImageContent::ImageContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node)
+ImageContent::ImageContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int)
        : Content (f, node)
        , VideoContent (f, node)
 {
index 3da7827252ffde805e8cddbdefb94c4682e08053..47c5a20e3486298e2e49d307a0136a21a4b80243 100644 (file)
@@ -31,7 +31,7 @@ class ImageContent : public VideoContent
 {
 public:
        ImageContent (boost::shared_ptr<const Film>, boost::filesystem::path);
-       ImageContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
+       ImageContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>, int);
 
        boost::shared_ptr<ImageContent> shared_from_this () {
                return boost::dynamic_pointer_cast<ImageContent> (Content::shared_from_this ());
index e2a3c34861a0e7f148c9e39fe34f55ddbb1eedd2..37b2902189f2b32d61a94a57bbc0baa36c7f0a28 100644 (file)
@@ -113,11 +113,11 @@ Playlist::video_identifier () const
 
 /** @param node <Playlist> node */
 void
-Playlist::set_from_xml (shared_ptr<const Film> film, shared_ptr<const cxml::Node> node)
+Playlist::set_from_xml (shared_ptr<const Film> film, shared_ptr<const cxml::Node> node, int version)
 {
        list<cxml::NodePtr> c = node->node_children ("Content");
        for (list<cxml::NodePtr>::iterator i = c.begin(); i != c.end(); ++i) {
-               _content.push_back (content_factory (film, *i));
+               _content.push_back (content_factory (film, *i, version));
        }
 
        sort (_content.begin(), _content.end(), ContentSorter ());
index a1ae9b151bfad4647fc6b9e4cd67158bbe0f8f53..f87b3397b4b68e388f3f5e0f37b512c385c4bcf5 100644 (file)
@@ -56,7 +56,7 @@ public:
        ~Playlist ();
 
        void as_xml (xmlpp::Node *);
-       void set_from_xml (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
+       void set_from_xml (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>, int);
 
        void add (boost::shared_ptr<Content>);
        void remove (boost::shared_ptr<Content>);
index 7069499641933bbb266a21532d72f2a0ce977d77..c7879202f471c6ac5a2f2f978215b35cffc39300 100644 (file)
@@ -43,7 +43,7 @@ SndfileContent::SndfileContent (shared_ptr<const Film> f, boost::filesystem::pat
 
 }
 
-SndfileContent::SndfileContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node)
+SndfileContent::SndfileContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node, int)
        : Content (f, node)
        , AudioContent (f, node)
        , _audio_mapping (node->node_child ("AudioMapping"))
index 191d625277307ea933fa13f1877ffa7494eab965..701ff16b24bd0dbbdf2d75e5708e2be3c7ce9e45 100644 (file)
@@ -33,7 +33,7 @@ class SndfileContent : public AudioContent
 {
 public:
        SndfileContent (boost::shared_ptr<const Film>, boost::filesystem::path);
-       SndfileContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
+       SndfileContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>, int);
 
        boost::shared_ptr<SndfileContent> shared_from_this () {
                return boost::dynamic_pointer_cast<SndfileContent> (Content::shared_from_this ());
index 7ae4f8b165c34b8195559b55fdc4d7a259c9d047..98dec58d7163d15d3614e319ef86408f9099a177 100644 (file)
@@ -91,6 +91,7 @@ using std::numeric_limits;
 using std::pair;
 using std::ofstream;
 using std::cout;
+using std::streampos;
 using boost::shared_ptr;
 using boost::thread;
 using boost::lexical_cast;
@@ -396,6 +397,11 @@ md5_digest (vector<boost::filesystem::path> files, shared_ptr<Job> job)
        MD5_CTX md5_context;
        MD5_Init (&md5_context);
 
+       vector<int64_t> sizes;
+       for (size_t i = 0; i < files.size(); ++i) {
+               sizes.push_back (boost::filesystem::file_size (files[i]));
+       }
+
        for (size_t i = 0; i < files.size(); ++i) {
                ifstream f (files[i].string().c_str(), std::ios::binary);
                if (!f.good ()) {
@@ -403,18 +409,19 @@ md5_digest (vector<boost::filesystem::path> files, shared_ptr<Job> job)
                }
        
                f.seekg (0, std::ios::end);
-               int bytes = f.tellg ();
+               streampos const bytes = f.tellg ();
                f.seekg (0, std::ios::beg);
 
-               while (bytes > 0) {
-                       int const t = min (bytes, buffer_size);
+               streampos remaining = bytes;
+               while (remaining > 0) {
+                       int const t = min (remaining, streampos (buffer_size));
                        f.read (buffer, t);
                        MD5_Update (&md5_context, buffer, t);
-                       bytes -= t;
-               }
+                       remaining -= t;
 
-               if (job) {
-                       job->set_progress (float (i) / files.size ());
+                       if (job) {
+                               job->set_progress ((float (i) + 1 - float(remaining) / bytes) / files.size ());
+                       }
                }
        }
 
index ca4ed8a9f019bcd9525997f779e76b5c33822af8..0a19ffd692463ac4f2923cd106ea54ddfccd4de1 100644 (file)
@@ -101,10 +101,11 @@ VideoContent::VideoContent (shared_ptr<const Film> f, shared_ptr<const cxml::Nod
 
 VideoContent::VideoContent (shared_ptr<const Film> f, vector<shared_ptr<Content> > c)
        : Content (f, c)
+       , _video_length (0)
 {
        shared_ptr<VideoContent> ref = dynamic_pointer_cast<VideoContent> (c[0]);
        assert (ref);
-       
+
        for (size_t i = 0; i < c.size(); ++i) {
                shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (c[i]);
 
@@ -131,6 +132,8 @@ VideoContent::VideoContent (shared_ptr<const Film> f, vector<shared_ptr<Content>
                if (vc->colour_conversion() != ref->colour_conversion()) {
                        throw JoinError (_("Content to be joined must have the same colour conversion."));
                }
+
+               _video_length += vc->video_length ();
        }
 
        _video_size = ref->video_size ();
index 1d01e4da8bf8b3fcead99504b9f7e8f2e311fedc..a4239bd2160e40861d6c47912d65c9e42aecb21c 100644 (file)
@@ -246,6 +246,7 @@ public:
        Frame (wxString const & title)
                : wxFrame (NULL, -1, title)
                , _servers_list_dialog (0)
+               , _hints_dialog (0)
        {
                wxMenuBar* bar = new wxMenuBar;
                setup_menu (bar);
index b3d28db5fcd823fa8918c70a18ffd98421d544b7..99d607731a6cb4372ac945903e72fd6663a54986 100644 (file)
@@ -820,7 +820,9 @@ FilmEditor::selected_content ()
                        break;
                }
 
-               sel.push_back (_film->content()[s]);
+               if (s < int (_film->content().size ())) {
+                       sel.push_back (_film->content()[s]);
+               }
        }
 
        return sel;
index 18b1f5451dc4bb460ba6265ea03841d7780c0040..668d713216e8ad49b1a40a8a9acd41b0ab7e62fd 100644 (file)
@@ -87,7 +87,7 @@ HintsDialog::film_changed ()
 
        if (vob > 1) {
                hint = true;
-               _text->WriteText (wxString::Format (_("You have %d files that look like they are VOB files from DVD.  You should coalesce them to ensure smooth joins between the files."), vob));
+               _text->WriteText (wxString::Format (_("You have %d files that look like they are VOB files from DVD. You should join them to ensure smooth joins between the files."), vob));
                _text->Newline ();
        }
 
index b56f133c7df1af8efb817a8231c0b78728833eb1..86bcc5a6939889bcfec87387c682256ad23f4cb6 100644 (file)
@@ -21,6 +21,7 @@
 #include <libxml++/libxml++.h>
 #include <libcxml/cxml.h>
 #include "lib/ffmpeg_content.h"
+#include "lib/film.h"
 
 using std::pair;
 using std::list;
@@ -61,7 +62,7 @@ BOOST_AUTO_TEST_CASE (stream_test)
                map->add_child("DCP")->add_child_text ("2");
        }
                
-       FFmpegAudioStream a (shared_ptr<cxml::Node> (new cxml::Node (root)));
+       FFmpegAudioStream a (shared_ptr<cxml::Node> (new cxml::Node (root)), Film::state_version);
 
        BOOST_CHECK_EQUAL (a.id, 4);
        BOOST_CHECK_EQUAL (a.frame_rate, 44100);