Merge master.
authorCarl Hetherington <cth@carlh.net>
Fri, 26 Apr 2013 22:49:54 +0000 (23:49 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 26 Apr 2013 22:49:54 +0000 (23:49 +0100)
36 files changed:
ChangeLog
debian/changelog
src/lib/ab_transcoder.cc
src/lib/ab_transcoder.h
src/lib/analyse_audio_job.cc
src/lib/analyse_audio_job.h
src/lib/audio_sink.h
src/lib/audio_source.cc
src/lib/audio_source.h
src/lib/combiner.cc
src/lib/combiner.h
src/lib/delay_line.cc
src/lib/delay_line.h
src/lib/encoder.cc
src/lib/encoder.h
src/lib/gain.cc
src/lib/gain.h
src/lib/image.cc
src/lib/image.h
src/lib/matcher.cc
src/lib/matcher.h
src/lib/transcoder.cc
src/lib/transcoder.h
src/lib/trimmer.cc
src/lib/trimmer.h
src/lib/util.cc
src/lib/util.h
src/lib/video_sink.h
src/lib/video_source.cc
src/lib/video_source.h
src/tools/makedcp.cc
src/tools/servomatictest.cc
src/wx/film_viewer.cc
src/wx/film_viewer.h
test/test.cc
wscript

index 8cabafd0bf76ef787a213f2b607e968f70d34b9b..129d148e9f76e1fb2cd97cf5afaad7557df44255 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,14 @@
        confirmation) and existing non-empty directories (with confirmation)
        (#124).
 
+2013-04-26  Carl Hetherington  <cth@carlh.net>
+
+       * Version 0.87 released.
+
+2013-04-26  Carl Hetherington  <cth@carlh.net>
+
+       * Make new trim options actually work (#121).
+
 2013-04-23  Carl Hetherington  <cth@carlh.net>
 
        * Version 0.86 released.
index 01fb12de4d7e7404aab5b82a7c945cb95bd374bf..83729c30929c4707736aabedbb586c81e0a2f749 100644 (file)
@@ -1,3 +1,9 @@
+dvdomatic (0.87-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Carl Hetherington <carl@houllier.lan>  Fri, 26 Apr 2013 09:53:27 +0100
+
 dvdomatic (0.86-1) UNRELEASED; urgency=low
 
   * New upstream release.
index 6eef397c245e69db4700ccc4454964b49ffabc33..d8f13dae4b7854afb0b1f4d97c70ab488f78ff2c 100644 (file)
@@ -32,6 +32,7 @@
 #include "delay_line.h"
 #include "gain.h"
 #include "combiner.h"
+#include "trimmer.h"
 
 /** @file src/ab_transcoder.cc
  *  @brief A transcoder which uses one Film for the left half of the screen, and a different one
@@ -61,26 +62,48 @@ ABTranscoder::ABTranscoder (
        _db = decoder_factory (_film_b, o);
 
        shared_ptr<AudioStream> st = _film_a->audio_stream();
-       _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->source_frame_rate()));
+       if (st) {
+               _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->source_frame_rate()));
+       }
        _delay_line.reset (new DelayLine (_film_a->log(), _film_a->audio_delay() / 1000.0f));
        _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain()));
 
+       int const sr = st ? st->sample_rate() : 0;
+       int const trim_start = _film_a->trim_type() == Film::ENCODE ? _film_a->trim_start() : 0;
+       int const trim_end = _film_a->trim_type() == Film::ENCODE ? _film_a->trim_end() : 0;
+       _trimmer.reset (new Trimmer (
+                               _film_a->log(), trim_start, trim_end, _film_a->length().get(),
+                               sr, _film_a->source_frame_rate(), _film_a->dcp_frame_rate()
+                               ));
+       
        /* Set up the decoder to use the film's set streams */
        _da.video->set_subtitle_stream (_film_a->subtitle_stream ());
        _db.video->set_subtitle_stream (_film_a->subtitle_stream ());
-       _da.audio->set_audio_stream (_film_a->audio_stream ());
+       if (_film_a->audio_stream ()) {
+               _da.audio->set_audio_stream (_film_a->audio_stream ());
+       }
 
        _da.video->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3, _4));
        _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4));
 
        _combiner->connect_video (_delay_line);
-       _delay_line->connect_video (_matcher);
-       _matcher->connect_video (_encoder);
+       if (_matcher) {
+               _delay_line->connect_video (_matcher);
+               _matcher->connect_video (_trimmer);
+       } else {
+               _delay_line->connect_video (_trimmer);
+       }
+       _trimmer->connect_video (_encoder);
        
        _da.audio->connect_audio (_delay_line);
-       _delay_line->connect_audio (_matcher);
-       _matcher->connect_audio (_gain);
-       _gain->connect_audio (_encoder);
+       if (_matcher) {
+               _delay_line->connect_audio (_matcher);
+               _matcher->connect_audio (_gain);
+       } else {
+               _delay_line->connect_audio (_gain);
+       }
+       _gain->connect_audio (_trimmer);
+       _trimmer->connect_audio (_encoder);
 }
 
 void
@@ -99,25 +122,21 @@ ABTranscoder::go ()
                } else {
                        done[2] = true;
                }
-
+               
                if (_job) {
                        _da.video->set_progress (_job);
                }
-
+               
                if (done[0] && done[1] && done[2]) {
                        break;
                }
        }
-
-       if (_delay_line) {
-               _delay_line->process_end ();
-       }
+               
+       _delay_line->process_end ();
        if (_matcher) {
                _matcher->process_end ();
        }
-       if (_gain) {
-               _gain->process_end ();
-       }
+       _gain->process_end ();
        _encoder->process_end ();
 }
                            
index 58a08af04ca7fbe67eddd78937af60c0fd53b51d..4f1b14e48ef27bea3072510ae58088046c784ca0 100644 (file)
@@ -39,6 +39,7 @@ class Matcher;
 class DelayLine;
 class Gain;
 class Combiner;
+class Trimmer;
 
 /** @class ABTranscoder
  *  @brief A transcoder which uses one Film for the left half of the screen, and a different one
@@ -68,5 +69,6 @@ private:
        boost::shared_ptr<Matcher> _matcher;
        boost::shared_ptr<DelayLine> _delay_line;
        boost::shared_ptr<Gain> _gain;
+       boost::shared_ptr<Trimmer> _trimmer;
        boost::shared_ptr<Image> _image;
 };
index 43eecbcbd774f66d4b84e70e714171aa86304aa2..88cd65fee64f0227d24960600b6664dc46721ae1 100644 (file)
@@ -84,7 +84,7 @@ AnalyseAudioJob::run ()
 }
 
 void
-AnalyseAudioJob::audio (shared_ptr<AudioBuffers> b)
+AnalyseAudioJob::audio (shared_ptr<const AudioBuffers> b)
 {
        for (int i = 0; i < b->frames(); ++i) {
                for (int j = 0; j < b->channels(); ++j) {
index dc1e073ee15a031552dc3975572ad2c8d9f97b2b..5435e0a7cfb5401fe5efc2901ac367f7b23c1826 100644 (file)
@@ -31,7 +31,7 @@ public:
        void run ();
 
 private:
-       void audio (boost::shared_ptr<AudioBuffers>);
+       void audio (boost::shared_ptr<const AudioBuffers>);
 
        int64_t _done;
        int64_t _samples_per_point;
index f34b24f88369feef2b23729390c9ec13b7818e9a..69b3a4b7522788d9739297506c1e135bd854328b 100644 (file)
@@ -24,14 +24,14 @@ class AudioSink
 {
 public:
        /** Call with some audio data */
-       virtual void process_audio (boost::shared_ptr<AudioBuffers>) = 0;
+       virtual void process_audio (boost::shared_ptr<const AudioBuffers>) = 0;
 };
 
 class TimedAudioSink
 {
 public:
         /** Call with some audio data */
-        virtual void process_audio (boost::shared_ptr<AudioBuffers>, double t) = 0;
+        virtual void process_audio (boost::shared_ptr<const AudioBuffers>, double t) = 0;
 };
 
 #endif
index bca3562cf974f36ea45077b1a08ed01142ea79a2..d77e89367b059de70606d953be86f9ca50dae6ca 100644 (file)
@@ -34,3 +34,9 @@ TimedAudioSource::connect_audio (shared_ptr<TimedAudioSink> s)
 {
        Audio.connect (bind (&TimedAudioSink::process_audio, s, _1, _2));
 }
+
+void
+TimedAudioSource::connect_audio (shared_ptr<AudioSink> s)
+{
+       Audio.connect (bind (&AudioSink::process_audio, s, _1));
+}
index 3dc998ccacd7156cf2f766b7f40dff009791fcb2..c13f1636b521661055ed18eb3c5daf89aaa44948 100644 (file)
@@ -35,7 +35,7 @@ class AudioSource
 {
 public:
        /** Emitted when some audio data is ready */
-       boost::signals2::signal<void (boost::shared_ptr<AudioBuffers>)> Audio;
+       boost::signals2::signal<void (boost::shared_ptr<const AudioBuffers>)> Audio;
 
        void connect_audio (boost::shared_ptr<AudioSink>);
 };
@@ -46,8 +46,9 @@ class TimedAudioSource
 {
 public:
        /** Emitted when some audio data is ready */
-       boost::signals2::signal<void (boost::shared_ptr<AudioBuffers>, double)> Audio;
+       boost::signals2::signal<void (boost::shared_ptr<const AudioBuffers>, double)> Audio;
 
+       void connect_audio (boost::shared_ptr<AudioSink>);
        void connect_audio (boost::shared_ptr<TimedAudioSink>);
 };
 
index 0a9eaf6b60bf8e12d2689ade030c7f16c50f0081..367cefa7f49fead4aa824798143fbf237dbeed74 100644 (file)
@@ -33,9 +33,9 @@ Combiner::Combiner (shared_ptr<Log> log)
  *  @param image Frame image.
  */
 void
-Combiner::process_video (shared_ptr<Image> image, bool, shared_ptr<Subtitle>, double)
+Combiner::process_video (shared_ptr<const Image> image, bool, shared_ptr<Subtitle>, double)
 {
-       _image = image;
+       _image.reset (new SimpleImage (image));
 }
 
 /** Process video for the right half of the frame.
@@ -43,22 +43,21 @@ Combiner::process_video (shared_ptr<Image> image, bool, shared_ptr<Subtitle>, do
  *  @param sub Subtitle (which will be put onto the whole frame)
  */
 void
-Combiner::process_video_b (shared_ptr<Image> image, bool, shared_ptr<Subtitle> sub, double t)
+Combiner::process_video_b (shared_ptr<const Image> image, bool, shared_ptr<Subtitle> sub, double t)
 {
        /* Copy the right half of this image into our _image */
        /* XXX: this should probably be in the Image class */
        for (int i = 0; i < image->components(); ++i) {
                int const line_size = image->line_size()[i];
                int const half_line_size = line_size / 2;
-               int const stride = image->stride()[i];
 
                uint8_t* p = _image->data()[i];
                uint8_t* q = image->data()[i];
                        
                for (int j = 0; j < image->lines (i); ++j) {
                        memcpy (p + half_line_size, q + half_line_size, half_line_size);
-                       p += stride;
-                       q += stride;
+                       p += _image->stride()[i];
+                       q += image->stride()[i];
                }
        }
 
index a8f1fa804e9bd1549e4dbb727875b71e3c353bcc..7ed316e26934cd663a0ab9ae92aa64d4ddca8952 100644 (file)
@@ -33,8 +33,8 @@ class Combiner : public TimedVideoProcessor
 public:
        Combiner (boost::shared_ptr<Log> log);
 
-       void process_video (boost::shared_ptr<Image> i, bool, boost::shared_ptr<Subtitle> s, double);
-       void process_video_b (boost::shared_ptr<Image> i, bool, boost::shared_ptr<Subtitle> s, double);
+       void process_video (boost::shared_ptr<const Image> i, bool, boost::shared_ptr<Subtitle> s, double);
+       void process_video_b (boost::shared_ptr<const Image> i, bool, boost::shared_ptr<Subtitle> s, double);
 
 private:
        /** The image that we are currently working on */
index 9e6baeba8131f0ebe671f0b9d3112466bfe1e5f8..b0180800a4625795823697c2dd5c9d1bfd2fcfff 100644 (file)
@@ -37,7 +37,7 @@ DelayLine::DelayLine (shared_ptr<Log> log, double seconds)
 }
 
 void
-DelayLine::process_audio (shared_ptr<AudioBuffers> data, double t)
+DelayLine::process_audio (shared_ptr<const AudioBuffers> data, double t)
 {
        if (_seconds > 0) {
                t += _seconds;
@@ -47,7 +47,7 @@ DelayLine::process_audio (shared_ptr<AudioBuffers> data, double t)
 }
 
 void
-DelayLine::process_video (boost::shared_ptr<Image> image, bool same, boost::shared_ptr<Subtitle> sub, double t)
+DelayLine::process_video (shared_ptr<const Image> image, bool same, boost::shared_ptr<Subtitle> sub, double t)
 {
        if (_seconds < 0) {
                t += _seconds;
index 90f1dcfa7b55b56fd1c42442d3b7fa0311a2fa56..781dce88a63938f611b76179029851eee0d6715c 100644 (file)
@@ -26,8 +26,8 @@ class DelayLine : public TimedAudioVideoProcessor
 public:
        DelayLine (boost::shared_ptr<Log> log, double);
        
-       void process_video (boost::shared_ptr<Image>, bool, boost::shared_ptr<Subtitle>, double);
-       void process_audio (boost::shared_ptr<AudioBuffers>, double);
+       void process_video (boost::shared_ptr<const Image>, bool, boost::shared_ptr<Subtitle>, double);
+       void process_audio (boost::shared_ptr<const AudioBuffers>, double);
 
 private:
        double _seconds;
index 7b338407eae7765c3bd7aac7bb5fd519b45675a7..cff9899acb6151cc19990f372c0a091c7d63968f 100644 (file)
@@ -231,7 +231,7 @@ Encoder::frame_done ()
 }
 
 void
-Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Subtitle> sub)
+Encoder::process_video (shared_ptr<const Image> image, bool same, boost::shared_ptr<Subtitle> sub)
 {
        FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate());
        
@@ -294,7 +294,7 @@ Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Su
 }
 
 void
-Encoder::process_audio (shared_ptr<AudioBuffers> data)
+Encoder::process_audio (shared_ptr<const AudioBuffers> data)
 {
 #if HAVE_SWRESAMPLE
        /* Maybe sample-rate convert */
@@ -333,7 +333,9 @@ Encoder::terminate_threads ()
        lock.unlock ();
 
        for (list<boost::thread *>::iterator i = _threads.begin(); i != _threads.end(); ++i) {
-               (*i)->join ();
+               if ((*i)->joinable ()) {
+                       (*i)->join ();
+               }
                delete *i;
        }
 }
index 86880bc34942561ba12a1488feb00663c2c9d6d8..70e81a7e071d483f3ae6bad45faf5b76f9c8c797 100644 (file)
@@ -73,10 +73,10 @@ public:
         *  @param same true if i is the same as the last time we were called.
         *  @param s A subtitle that should be on this frame, or 0.
         */
-       void process_video (boost::shared_ptr<Image> i, bool same, boost::shared_ptr<Subtitle> s);
+       void process_video (boost::shared_ptr<const Image> i, bool same, boost::shared_ptr<Subtitle> s);
 
        /** Call with some audio data */
-       void process_audio (boost::shared_ptr<AudioBuffers>);
+       void process_audio (boost::shared_ptr<const AudioBuffers>);
 
        /** Called when a processing run has finished */
        virtual void process_end ();
index df7011d2e8100a14e537234d9e6d6fb0e2fb8d57..ccd779d7154f1b9813fb8754ee67abacc19064cd 100644 (file)
@@ -30,7 +30,7 @@ Gain::Gain (shared_ptr<Log> log, float gain)
 }
 
 void
-Gain::process_audio (shared_ptr<AudioBuffers> b)
+Gain::process_audio (shared_ptr<const AudioBuffers> b)
 {
        if (_gain != 0) {
                float const linear_gain = pow (10, _gain / 20);
index d462e5aeee2471988d203cee7805c8c2f458c400..61fef5e85a8236eece5b94f4453b69745a781c9d 100644 (file)
@@ -24,7 +24,7 @@ class Gain : public AudioProcessor
 public:
        Gain (boost::shared_ptr<Log> log, float gain);
 
-       void process_audio (boost::shared_ptr<AudioBuffers>);
+       void process_audio (boost::shared_ptr<const AudioBuffers>);
 
 private:
        float _gain;
index 2355d22e5b959ab12af8c9f8bae144d781649315..1be41fecf880dffaaa5f8ddbfafd20ec5296e175 100644 (file)
@@ -509,7 +509,33 @@ SimpleImage::SimpleImage (SimpleImage const & other)
        allocate ();
 
        for (int i = 0; i < components(); ++i) {
-               memcpy (_data[i], other._data[i], _line_size[i] * lines(i));
+               uint8_t* p = _data[i];
+               uint8_t* q = other._data[i];
+               for (int j = 0; j < lines(i); ++j) {
+                       memcpy (p, q, _line_size[i]);
+                       p += stride()[i];
+                       q += other.stride()[i];
+               }
+       }
+}
+
+SimpleImage::SimpleImage (shared_ptr<const Image> other)
+       : Image (*other.get())
+{
+       _size = other->size ();
+       _aligned = true;
+
+       allocate ();
+
+       for (int i = 0; i < components(); ++i) {
+               assert(line_size()[i] == other->line_size()[i]);
+               uint8_t* p = _data[i];
+               uint8_t* q = other->data()[i];
+               for (int j = 0; j < lines(i); ++j) {
+                       memcpy (p, q, line_size()[i]);
+                       p += stride()[i];
+                       q += other->stride()[i];
+               }
        }
 }
 
index 6b9ade99eefccb8b3d92e7c023300c14f9ac9601..62961a92e12d56cd5d9ac658bb12d1c47e27658d 100644 (file)
@@ -131,6 +131,7 @@ class SimpleImage : public Image
 public:
        SimpleImage (AVPixelFormat, libdcp::Size, bool);
        SimpleImage (SimpleImage const &);
+       SimpleImage (boost::shared_ptr<const Image>);
        SimpleImage& operator= (SimpleImage const &);
        ~SimpleImage ();
 
index 34ddc86d6d931eb0b6f61e8eba4c7abd0d68f651..9924c003ae5b81298ef27653e5ba015d7d312307 100644 (file)
@@ -41,7 +41,7 @@ Matcher::Matcher (shared_ptr<Log> log, int sample_rate, float frames_per_second)
 }
 
 void
-Matcher::process_video (boost::shared_ptr<Image> image, bool same, boost::shared_ptr<Subtitle> sub, double t)
+Matcher::process_video (boost::shared_ptr<const Image> image, bool same, boost::shared_ptr<Subtitle> sub, double t)
 {
        _pixel_format = image->pixel_format ();
        _size = image->size ();
@@ -90,11 +90,15 @@ Matcher::process_video (boost::shared_ptr<Image> image, bool same, boost::shared
 }
 
 void
-Matcher::process_audio (boost::shared_ptr<AudioBuffers> b, double t)
+Matcher::process_audio (boost::shared_ptr<const AudioBuffers> b, double t)
 {
        _channels = b->channels ();
 
-       _log->log (String::compose ("Matcher audio @ %1 [video=%2, audio=%3, pending_audio=%4]", t, _video_frames, _audio_frames, _pending_audio.size()));
+       _log->log (String::compose (
+                          "Matcher audio (%1 frames) @ %2 [video=%3, audio=%4, pending_audio=%5]",
+                          b->frames(), t, _video_frames, _audio_frames, _pending_audio.size()
+                          )
+               );
 
        if (!_first_input) {
                _first_input = t;
@@ -198,8 +202,9 @@ void
 Matcher::repeat_last_video ()
 {
        if (!_last_image) {
-               _last_image.reset (new SimpleImage (_pixel_format.get(), _size.get(), true));
-               _last_image->make_black ();
+               shared_ptr<Image> im (new SimpleImage (_pixel_format.get(), _size.get(), true));
+               im->make_black ();
+               _last_image = im;
        }
 
        Video (_last_image, true, _last_subtitle);
index f54aa4b6a7c9c37815697fcd03c55b9936936353..41aa373a412cd51808dc5d7967e3c04640cc7a80 100644 (file)
@@ -25,8 +25,8 @@ class Matcher : public Processor, public TimedAudioSink, public TimedVideoSink,
 {
 public:
        Matcher (boost::shared_ptr<Log> log, int sample_rate, float frames_per_second);
-       void process_video (boost::shared_ptr<Image> i, bool, boost::shared_ptr<Subtitle> s, double);
-       void process_audio (boost::shared_ptr<AudioBuffers>, double);
+       void process_video (boost::shared_ptr<const Image> i, bool, boost::shared_ptr<Subtitle> s, double);
+       void process_audio (boost::shared_ptr<const AudioBuffers>, double);
        void process_end ();
 
 private:
@@ -43,19 +43,19 @@ private:
        boost::optional<int> _channels;
 
        struct AudioRecord {
-               AudioRecord (boost::shared_ptr<AudioBuffers> a, double t)
+               AudioRecord (boost::shared_ptr<const AudioBuffers> a, double t)
                        : audio (a)
                        , time (t)
                {}
                
-               boost::shared_ptr<AudioBuffers> audio;
+               boost::shared_ptr<const AudioBuffers> audio;
                double time;
        };
 
        std::list<AudioRecord> _pending_audio;
 
        boost::optional<double> _first_input;
-       boost::shared_ptr<Image> _last_image;
+       boost::shared_ptr<const Image> _last_image;
        boost::shared_ptr<Subtitle> _last_subtitle;
 
        bool _had_first_video;
index e00b2f1e090ff09f55caab5e3c58a0edcf445c17..faafcaf8b593821fd6b5600f82f48b758192eeba 100644 (file)
@@ -36,6 +36,7 @@
 #include "gain.h"
 #include "video_decoder.h"
 #include "audio_decoder.h"
+#include "trimmer.h"
 
 using std::string;
 using boost::shared_ptr;
@@ -61,6 +62,14 @@ Transcoder::Transcoder (shared_ptr<Film> f, DecodeOptions o, Job* j, shared_ptr<
        _delay_line.reset (new DelayLine (f->log(), f->audio_delay() / 1000.0f));
        _gain.reset (new Gain (f->log(), f->audio_gain()));
 
+       int const sr = st ? st->sample_rate() : 0;
+       int const trim_start = f->trim_type() == Film::ENCODE ? f->trim_start() : 0;
+       int const trim_end = f->trim_type() == Film::ENCODE ? f->trim_end() : 0;
+       _trimmer.reset (new Trimmer (
+                               f->log(), trim_start, trim_end, f->length().get_value_or(0),
+                               sr, f->source_frame_rate(), f->dcp_frame_rate()
+                               ));
+
        /* Set up the decoder to use the film's set streams */
        _decoders.video->set_subtitle_stream (f->subtitle_stream ());
        if (f->audio_stream ()) {
@@ -70,19 +79,21 @@ Transcoder::Transcoder (shared_ptr<Film> f, DecodeOptions o, Job* j, shared_ptr<
        _decoders.video->connect_video (_delay_line);
        if (_matcher) {
                _delay_line->connect_video (_matcher);
-               _matcher->connect_video (_encoder);
+               _matcher->connect_video (_trimmer);
        } else {
-               _delay_line->Video.connect (bind (&Encoder::process_video, _encoder, _1, _2, _3));
+               _delay_line->connect_video (_trimmer);
        }
+       _trimmer->connect_video (_encoder);
        
        _decoders.audio->connect_audio (_delay_line);
        if (_matcher) {
                _delay_line->connect_audio (_matcher);
                _matcher->connect_audio (_gain);
        } else {
-               _delay_line->Audio.connect (bind (&Encoder::process_audio, _encoder, _1));
+               _delay_line->connect_audio (_gain);
        }
-       _gain->connect_audio (_encoder);
+       _gain->connect_audio (_trimmer);
+       _trimmer->connect_audio (_encoder);
 }
 
 /** Run the decoder, passing its output to the encoder, until the decoder
@@ -92,31 +103,26 @@ void
 Transcoder::go ()
 {
        _encoder->process_begin ();
-       try {
-               bool done[2] = { false, false };
-               
-               while (1) {
-                       if (!done[0]) {
-                               done[0] = _decoders.video->pass ();
-                               if (_job) {
-                                       _decoders.video->set_progress (_job);
-                               }
-                       }
-
-                       if (!done[1] && _decoders.audio && dynamic_pointer_cast<Decoder> (_decoders.audio) != dynamic_pointer_cast<Decoder> (_decoders.video)) {
-                               done[1] = _decoders.audio->pass ();
-                       } else {
-                               done[1] = true;
-                       }
 
-                       if (done[0] && done[1]) {
-                               break;
+       bool done[2] = { false, false };
+       
+       while (1) {
+               if (!done[0]) {
+                       done[0] = _decoders.video->pass ();
+                       if (_job) {
+                               _decoders.video->set_progress (_job);
                        }
                }
                
-       } catch (...) {
-               _encoder->process_end ();
-               throw;
+               if (!done[1] && _decoders.audio && dynamic_pointer_cast<Decoder> (_decoders.audio) != dynamic_pointer_cast<Decoder> (_decoders.video)) {
+                       done[1] = _decoders.audio->pass ();
+               } else {
+                       done[1] = true;
+               }
+               
+               if (done[0] && done[1]) {
+                       break;
+               }
        }
        
        _delay_line->process_end ();
index b0c263d07823f6450a6daa725a63bb6852df5976..f5b8ae6e329d3892735bf5d5a4d36f1615c44fc5 100644 (file)
@@ -35,6 +35,7 @@ class Gain;
 class VideoDecoder;
 class AudioDecoder;
 class DelayLine;
+class Trimmer;
 
 /** @class Transcoder
  *  @brief A class which takes a Film and some Options, then uses those to transcode the film.
@@ -68,4 +69,5 @@ protected:
        boost::shared_ptr<Matcher> _matcher;
        boost::shared_ptr<DelayLine> _delay_line;
        boost::shared_ptr<Gain> _gain;
+       boost::shared_ptr<Trimmer> _trimmer;
 };
index 68364e50ad91f8dbbbd4a8e6792b933d439bb32f..b7afc9299452708e6a3f4d96e44a6dc070199225 100644 (file)
@@ -28,7 +28,8 @@ using boost::shared_ptr;
 Trimmer::Trimmer (
        shared_ptr<Log> log,
        int video_trim_start,
-       int video_trim_end, int video_length,
+       int video_trim_end,
+       int video_length,
        int audio_sample_rate,
        float frames_per_second,
        int dcp_frames_per_second
@@ -53,12 +54,19 @@ Trimmer::Trimmer (
                _audio_start = video_frames_to_audio_frames (_video_start, audio_sample_rate, frames_per_second);
                _audio_end = video_frames_to_audio_frames (_video_end, audio_sample_rate, frames_per_second);
        }
+
+       /* XXX: this is a hack; this flag means that no trim is happening at the end of the film, and I'm
+          using that to prevent audio trim being rounded to video trim, which breaks the current set
+          of regression tests.  This could be removed if a) the regression tests are regenerated and b)
+          I can work out what DCP length should be.
+       */
+       _no_trim = (_video_start == 0) && (_video_end == (video_length - video_trim_end));
 }
 
 void
-Trimmer::process_video (shared_ptr<Image> image, bool same, shared_ptr<Subtitle> sub)
+Trimmer::process_video (shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub)
 {
-       if (_video_in >= _video_start && _video_in <= _video_end) {
+       if (_no_trim || (_video_in >= _video_start && _video_in <= _video_end)) {
                Video (image, same, sub);
        }
        
@@ -66,8 +74,13 @@ Trimmer::process_video (shared_ptr<Image> image, bool same, shared_ptr<Subtitle>
 }
 
 void
-Trimmer::process_audio (shared_ptr<AudioBuffers> audio)
+Trimmer::process_audio (shared_ptr<const AudioBuffers> audio)
 {
+       if (_no_trim) {
+               Audio (audio);
+               return;
+       }
+       
        int64_t offset = _audio_start - _audio_in;
        if (offset > audio->frames()) {
                _audio_in += audio->frames ();
@@ -91,8 +104,10 @@ Trimmer::process_audio (shared_ptr<AudioBuffers> audio)
        _audio_in += audio->frames ();
        
        if (offset != 0 || length != audio->frames ()) {
-               audio->move (offset, 0, length);
-               audio->set_frames (length);
+               shared_ptr<AudioBuffers> copy (new AudioBuffers (audio));
+               copy->move (offset, 0, length);
+               copy->set_frames (length);
+               audio = copy;
        }
        
        Audio (audio);
index ff7e9514d1e1d13e5bcda9cb1a13b1e3895ed781..98a118fb27abe784366efecb64bf59b4204dda23 100644 (file)
@@ -24,8 +24,8 @@ class Trimmer : public AudioVideoProcessor
 public:
        Trimmer (boost::shared_ptr<Log>, int, int, int, int, float, int);
 
-       void process_video (boost::shared_ptr<Image> i, bool, boost::shared_ptr<Subtitle> s);
-       void process_audio (boost::shared_ptr<AudioBuffers>);
+       void process_video (boost::shared_ptr<const Image> i, bool, boost::shared_ptr<Subtitle> s);
+       void process_audio (boost::shared_ptr<const AudioBuffers>);
 
 private:
        friend class trimmer_test;
@@ -36,4 +36,5 @@ private:
        int64_t _audio_start;
        int64_t _audio_end;
        int64_t _audio_in;
+       bool _no_trim;
 };
index e43b598ab3ef3e635baac415cce0ad7f511c47fd..859aa6de7ddda8efa646ee695247023d40169a7a 100644 (file)
@@ -63,11 +63,24 @@ extern "C" {
 
 #include "i18n.h"
 
-using namespace std;
-using namespace boost;
+using std::cout;
+using std::string;
+using std::stringstream;
+using std::list;
+using std::ostream;
+using std::vector;
+using std::ifstream;
+using std::istream;
+using std::min;
+using std::max;
+using std::multimap;
+using std::pair;
+using boost::shared_ptr;
+using boost::lexical_cast;
+using boost::optional;
 using libdcp::Size;
 
-thread::id ui_thread;
+boost::thread::id ui_thread;
 
 /** Convert some number of seconds to a string representation
  *  in hours, minutes and seconds.
@@ -87,9 +100,9 @@ seconds_to_hms (int s)
        stringstream hms;
        hms << h << N_(":");
        hms.width (2);
-       hms << setfill ('0') << m << N_(":");
+       hms << std::setfill ('0') << m << N_(":");
        hms.width (2);
-       hms << setfill ('0') << s;
+       hms << std::setfill ('0') << s;
 
        return hms.str ();
 }
@@ -185,7 +198,7 @@ stacktrace (ostream& out, int levels)
      
        if (strings) {
                for (i = 0; i < size && (levels == 0 || i < size_t(levels)); i++) {
-                       out << N_("  ") << demangle (strings[i]) << endl;
+                       out << N_("  ") << demangle (strings[i]) << "\n";
                }
                
                free (strings);
@@ -243,7 +256,7 @@ dvdomatic_setup ()
        Filter::setup_filters ();
        SoundProcessor::setup_sound_processors ();
 
-       ui_thread = this_thread::get_id ();
+       ui_thread = boost::this_thread::get_id ();
 }
 
 #ifdef DVDOMATIC_WINDOWS
@@ -338,7 +351,7 @@ md5_digest (void const * data, int size)
        
        stringstream s;
        for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
-               s << hex << setfill('0') << setw(2) << ((int) digest[i]);
+               s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]);
        }
 
        return s.str ();
@@ -350,14 +363,14 @@ md5_digest (void const * data, int size)
 string
 md5_digest (string file)
 {
-       ifstream f (file.c_str(), ios::binary);
+       ifstream f (file.c_str(), std::ios::binary);
        if (!f.good ()) {
                throw OpenFileError (file);
        }
        
-       f.seekg (0, ios::end);
+       f.seekg (0, std::ios::end);
        int bytes = f.tellg ();
-       f.seekg (0, ios::beg);
+       f.seekg (0, std::ios::beg);
 
        int const buffer_size = 64 * 1024;
        char buffer[buffer_size];
@@ -376,7 +389,7 @@ md5_digest (string file)
 
        stringstream s;
        for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
-               s << hex << setfill('0') << setw(2) << ((int) digest[i]);
+               s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]);
        }
 
        return s.str ();
@@ -441,8 +454,8 @@ best_dcp_frame_rate (float source_fps)
        }
 
        /* Pick the best one, bailing early if we hit an exact match */
-       float error = numeric_limits<float>::max ();
-       boost::optional<FrameRateCandidate> best;
+       float error = std::numeric_limits<float>::max ();
+       optional<FrameRateCandidate> best;
        list<FrameRateCandidate>::iterator i = candidates.begin();
        while (i != candidates.end()) {
                
@@ -509,16 +522,16 @@ Socket::Socket (int timeout)
        , _socket (_io_service)
        , _timeout (timeout)
 {
-       _deadline.expires_at (posix_time::pos_infin);
+       _deadline.expires_at (boost::posix_time::pos_infin);
        check ();
 }
 
 void
 Socket::check ()
 {
-       if (_deadline.expires_at() <= asio::deadline_timer::traits_type::now ()) {
+       if (_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now ()) {
                _socket.close ();
-               _deadline.expires_at (posix_time::pos_infin);
+               _deadline.expires_at (boost::posix_time::pos_infin);
        }
 
        _deadline.async_wait (boost::bind (&Socket::check, this));
@@ -528,14 +541,14 @@ Socket::check ()
  *  @param endpoint End-point to connect to.
  */
 void
-Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint)
+Socket::connect (boost::asio::ip::basic_resolver_entry<boost::asio::ip::tcp> const & endpoint)
 {
-       _deadline.expires_from_now (posix_time::seconds (_timeout));
-       system::error_code ec = asio::error::would_block;
-       _socket.async_connect (endpoint, lambda::var(ec) = lambda::_1);
+       _deadline.expires_from_now (boost::posix_time::seconds (_timeout));
+       boost::system::error_code ec = boost::asio::error::would_block;
+       _socket.async_connect (endpoint, boost::lambda::var(ec) = boost::lambda::_1);
        do {
                _io_service.run_one();
-       } while (ec == asio::error::would_block);
+       } while (ec == boost::asio::error::would_block);
 
        if (ec || !_socket.is_open ()) {
                throw NetworkError (_("connect timed out"));
@@ -549,14 +562,14 @@ Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint)
 void
 Socket::write (uint8_t const * data, int size)
 {
-       _deadline.expires_from_now (posix_time::seconds (_timeout));
-       system::error_code ec = asio::error::would_block;
+       _deadline.expires_from_now (boost::posix_time::seconds (_timeout));
+       boost::system::error_code ec = boost::asio::error::would_block;
 
-       asio::async_write (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1);
+       boost::asio::async_write (_socket, boost::asio::buffer (data, size), boost::lambda::var(ec) = boost::lambda::_1);
        
        do {
                _io_service.run_one ();
-       } while (ec == asio::error::would_block);
+       } while (ec == boost::asio::error::would_block);
 
        if (ec) {
                throw NetworkError (ec.message ());
@@ -577,14 +590,14 @@ Socket::write (uint32_t v)
 void
 Socket::read (uint8_t* data, int size)
 {
-       _deadline.expires_from_now (posix_time::seconds (_timeout));
-       system::error_code ec = asio::error::would_block;
+       _deadline.expires_from_now (boost::posix_time::seconds (_timeout));
+       boost::system::error_code ec = boost::asio::error::would_block;
 
-       asio::async_read (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1);
+       boost::asio::async_read (_socket, boost::asio::buffer (data, size), boost::lambda::var(ec) = boost::lambda::_1);
 
        do {
                _io_service.run_one ();
-       } while (ec == asio::error::would_block);
+       } while (ec == boost::asio::error::would_block);
        
        if (ec) {
                throw NetworkError (ec.message ());
@@ -761,6 +774,21 @@ AudioBuffers::AudioBuffers (AudioBuffers const & other)
        }
 }
 
+/* XXX: it's a shame that this is a copy-and-paste of the above;
+   probably fixable with c++0x.
+*/
+AudioBuffers::AudioBuffers (boost::shared_ptr<const AudioBuffers> other)
+       : _channels (other->_channels)
+       , _frames (other->_frames)
+       , _allocated_frames (other->_frames)
+{
+       _data = new float*[_channels];
+       for (int i = 0; i < _channels; ++i) {
+               _data[i] = new float[_frames];
+               memcpy (_data[i], other->_data[i], _frames * sizeof (float));
+       }
+}
+
 /** AudioBuffers destructor */
 AudioBuffers::~AudioBuffers ()
 {
@@ -865,7 +893,7 @@ AudioBuffers::move (int from, int to, int frames)
 void
 ensure_ui_thread ()
 {
-       assert (this_thread::get_id() == ui_thread);
+       assert (boost::this_thread::get_id() == ui_thread);
 }
 
 /** @param v Source video frame.
index 31d0fc96707fb976759fed42e69b51225a845389..99670110edec6d4d47eaf6c4709c60d3be3e5f8c 100644 (file)
@@ -241,6 +241,7 @@ class AudioBuffers
 public:
        AudioBuffers (int channels, int frames);
        AudioBuffers (AudioBuffers const &);
+       AudioBuffers (boost::shared_ptr<const AudioBuffers>);
        ~AudioBuffers ();
 
        float** data () const {
index 32c7f3b384f145cbb1bf83ba6de63294675fa253..0170c7350c90d1f1898c9a275b7d21556fc4c2e5 100644 (file)
@@ -34,7 +34,7 @@ public:
         *  @param same true if i is the same as last time we were called.
         *  @param s A subtitle that should be on this frame, or 0.
         */
-       virtual void process_video (boost::shared_ptr<Image> i, bool same, boost::shared_ptr<Subtitle> s) = 0;
+       virtual void process_video (boost::shared_ptr<const Image> i, bool same, boost::shared_ptr<Subtitle> s) = 0;
 };
 
 class TimedVideoSink
@@ -46,7 +46,7 @@ public:
         *  @param s A subtitle that should be on this frame, or 0.
         *  @param t Source timestamp.
         */
-       virtual void process_video (boost::shared_ptr<Image> i, bool same, boost::shared_ptr<Subtitle> s, double t) = 0;
+       virtual void process_video (boost::shared_ptr<const Image> i, bool same, boost::shared_ptr<Subtitle> s, double t) = 0;
 };
 
 #endif
index af6f941fd1f3f00a2b6ea2055e879bd75ddbf337..539243402e0824f7551940fe0cb12d2313d77acf 100644 (file)
@@ -34,3 +34,11 @@ TimedVideoSource::connect_video (shared_ptr<TimedVideoSink> s)
 {
        Video.connect (bind (&TimedVideoSink::process_video, s, _1, _2, _3, _4));
 }
+
+void
+TimedVideoSource::connect_video (shared_ptr<VideoSink> s)
+{
+       Video.connect (bind (&VideoSink::process_video, s, _1, _2, _3));
+}
+
+       
index 705b0023aec3037877a60e5e7af16db1a854d97e..748cb6fe98b403cda07b939568ef8971eec7993a 100644 (file)
@@ -45,7 +45,7 @@ public:
         *  Second parameter is true if the image is the same as the last one that was emitted.
         *  Third parameter is either 0 or a subtitle that should be on this frame.
         */
-       boost::signals2::signal<void (boost::shared_ptr<Image>, bool, boost::shared_ptr<Subtitle>)> Video;
+       boost::signals2::signal<void (boost::shared_ptr<const Image>, bool, boost::shared_ptr<Subtitle>)> Video;
 
        void connect_video (boost::shared_ptr<VideoSink>);
 };
@@ -63,8 +63,9 @@ public:
         *  Third parameter is either 0 or a subtitle that should be on this frame.
         *  Fourth parameter is the source timestamp of this frame.
         */
-       boost::signals2::signal<void (boost::shared_ptr<Image>, bool, boost::shared_ptr<Subtitle>, double)> Video;
+       boost::signals2::signal<void (boost::shared_ptr<const Image>, bool, boost::shared_ptr<Subtitle>, double)> Video;
 
+       void connect_video (boost::shared_ptr<VideoSink>);
        void connect_video (boost::shared_ptr<TimedVideoSink>);
 };
 
index 0c639077162250cb31b11fa58e9a84f7b5f347d8..c594991a6bf41b5738e5617754d9365cdaad6da3 100644 (file)
@@ -64,7 +64,7 @@ main (int argc, char* argv[])
        bool test_mode = false;
        bool progress = true;
        bool no_remote = false;
-       int log_level = 1;
+       int log_level = 0;
 
        int option_index = 0;
        while (1) {
index f5756c6939e7770fc12040838fc2c7b7c0030ad3..5e1cf49b4b0b1e04faff88718f58801948492173 100644 (file)
@@ -47,7 +47,7 @@ static shared_ptr<FileLog> log_ (new FileLog ("servomatictest.log"));
 static int frame = 0;
 
 void
-process_video (shared_ptr<Image> image, bool, shared_ptr<Subtitle> sub)
+process_video (shared_ptr<const Image> image, bool, shared_ptr<Subtitle> sub)
 {
        shared_ptr<DCPVideoFrame> local (
                new DCPVideoFrame (
index 8508ec2a21beec19832255432e1cc118ef18550f..4f2985a061db3677ebfb6d0ed5c89bf2fd25c9f8 100644 (file)
@@ -308,7 +308,7 @@ FilmViewer::raw_to_display ()
                return;
        }
 
-       boost::shared_ptr<Image> input = _raw_frame;
+       boost::shared_ptr<const Image> input = _raw_frame;
 
        pair<string, string> const s = Filter::ffmpeg_strings (_film->filters());
        if (!s.second.empty ()) {
@@ -400,7 +400,7 @@ FilmViewer::check_play_state ()
 }
 
 void
-FilmViewer::process_video (shared_ptr<Image> image, bool, shared_ptr<Subtitle> sub, double t)
+FilmViewer::process_video (shared_ptr<const Image> image, bool, shared_ptr<Subtitle> sub, double t)
 {
        _raw_frame = image;
        _raw_sub = sub;
index a78c772a49858570f9dd0170e6cf8dd5a752460c..ed5874fbcc6f945d6285db27bbe74801998fb893 100644 (file)
@@ -48,7 +48,7 @@ private:
        void slider_moved (wxScrollEvent &);
        void play_clicked (wxCommandEvent &);
        void timer (wxTimerEvent &);
-       void process_video (boost::shared_ptr<Image>, bool, boost::shared_ptr<Subtitle>, double);
+       void process_video (boost::shared_ptr<const Image>, bool, boost::shared_ptr<Subtitle>, double);
        void calculate_sizes ();
        void check_play_state ();
        void update_from_raw ();
@@ -72,9 +72,9 @@ private:
        wxTimer _timer;
 
        Decoders _decoders;
-       boost::shared_ptr<Image> _raw_frame;
+       boost::shared_ptr<const Image> _raw_frame;
        boost::shared_ptr<Subtitle> _raw_sub;
-       boost::shared_ptr<Image> _display_frame;
+       boost::shared_ptr<const Image> _display_frame;
        /* The x offset at which we display the actual film content; this corresponds
           to the film's padding converted to our coordinates.
        */
index b0b2cef7d057fe0e43167d1889c563f372c51f53..496c915198818753036d2864656cd26aa75693e8 100644 (file)
@@ -123,52 +123,77 @@ BOOST_AUTO_TEST_CASE (make_black_test)
        }
 }
 
-shared_ptr<AudioBuffers> trimmer_test_last;
+shared_ptr<const Image> trimmer_test_last_video;
+shared_ptr<const AudioBuffers> trimmer_test_last_audio;
 
 void
-trimmer_test_helper (shared_ptr<AudioBuffers> audio)
+trimmer_test_video_helper (shared_ptr<const Image> image, bool, shared_ptr<Subtitle>)
 {
-       trimmer_test_last = audio;
+       trimmer_test_last_video = image;
 }
 
+void
+trimmer_test_audio_helper (shared_ptr<const AudioBuffers> audio)
+{
+       trimmer_test_last_audio = audio;
+}
+
+BOOST_AUTO_TEST_CASE (trimmer_passthrough_test)
+{
+       Trimmer trimmer (shared_ptr<Log> (), 0, 0, 200, 48000, 25, 25);
+       trimmer.Video.connect (bind (&trimmer_test_video_helper, _1, _2, _3));
+       trimmer.Audio.connect (bind (&trimmer_test_audio_helper, _1));
+
+       shared_ptr<SimpleImage> video (new SimpleImage (PIX_FMT_RGB24, libdcp::Size (1998, 1080), true));
+       shared_ptr<AudioBuffers> audio (new AudioBuffers (6, 42 * 1920));
+
+       trimmer.process_video (video, false, shared_ptr<Subtitle> ());
+       trimmer.process_audio (audio);
+
+       BOOST_CHECK_EQUAL (video.get(), trimmer_test_last_video.get());
+       BOOST_CHECK_EQUAL (audio.get(), trimmer_test_last_audio.get());
+       BOOST_CHECK_EQUAL (audio->frames(), trimmer_test_last_audio->frames());
+}
+
+
 /** Test the audio handling of the Trimmer */
-BOOST_AUTO_TEST_CASE (trimmer_test)
+BOOST_AUTO_TEST_CASE (trimmer_audio_test)
 {
        Trimmer trimmer (shared_ptr<Log> (), 25, 75, 200, 48000, 25, 25);
 
-       trimmer.Audio.connect (bind (&trimmer_test_helper, _1));
+       trimmer.Audio.connect (bind (&trimmer_test_audio_helper, _1));
 
        /* 21 video frames-worth of audio frames; should be completely stripped */
-       trimmer_test_last.reset ();
+       trimmer_test_last_audio.reset ();
        shared_ptr<AudioBuffers> audio (new AudioBuffers (6, 21 * 1920));
        trimmer.process_audio (audio);
-       BOOST_CHECK (trimmer_test_last == 0);
+       BOOST_CHECK (trimmer_test_last_audio == 0);
 
        /* 42 more video frames-worth, 4 should be stripped from the start */
        audio.reset (new AudioBuffers (6, 42 * 1920));
        trimmer.process_audio (audio);
-       BOOST_CHECK (trimmer_test_last);
-       BOOST_CHECK_EQUAL (trimmer_test_last->frames(), 38 * 1920);
+       BOOST_CHECK (trimmer_test_last_audio);
+       BOOST_CHECK_EQUAL (trimmer_test_last_audio->frames(), 38 * 1920);
 
        /* 42 more video frames-worth, should be kept as-is */
-       trimmer_test_last.reset ();
+       trimmer_test_last_audio.reset ();
        audio.reset (new AudioBuffers (6, 42 * 1920));
        trimmer.process_audio (audio);
-       BOOST_CHECK (trimmer_test_last);
-       BOOST_CHECK_EQUAL (trimmer_test_last->frames(), 42 * 1920);
+       BOOST_CHECK (trimmer_test_last_audio);
+       BOOST_CHECK_EQUAL (trimmer_test_last_audio->frames(), 42 * 1920);
 
        /* 25 more video frames-worth, 5 should be trimmed from the end */
-       trimmer_test_last.reset ();
+       trimmer_test_last_audio.reset ();
        audio.reset (new AudioBuffers (6, 25 * 1920));
        trimmer.process_audio (audio);
-       BOOST_CHECK (trimmer_test_last);
-       BOOST_CHECK_EQUAL (trimmer_test_last->frames(), 20 * 1920);
+       BOOST_CHECK (trimmer_test_last_audio);
+       BOOST_CHECK_EQUAL (trimmer_test_last_audio->frames(), 20 * 1920);
 
        /* Now some more; all should be trimmed */
-       trimmer_test_last.reset ();
+       trimmer_test_last_audio.reset ();
        audio.reset (new AudioBuffers (6, 100 * 1920));
        trimmer.process_audio (audio);
-       BOOST_CHECK (trimmer_test_last == 0);
+       BOOST_CHECK (trimmer_test_last_audio == 0);
 }
 
 
diff --git a/wscript b/wscript
index 2de1cfd71d4503ee7a50e79792477b9c2a38a796..9e977157d7dfb04c2bc6f1ffaeb9272200f7a0e2 100644 (file)
--- a/wscript
+++ b/wscript
@@ -3,7 +3,7 @@ import os
 import sys
 
 APPNAME = 'dvdomatic'
-VERSION = '0.87pre'
+VERSION = '0.88pre'
 
 def options(opt):
     opt.load('compiler_cxx')