operator bool on Time is a really bad idea; removed it and fixed lots of bugs.
authorCarl Hetherington <cth@carlh.net>
Fri, 7 Mar 2014 10:57:33 +0000 (10:57 +0000)
committerCarl Hetherington <cth@carlh.net>
Fri, 7 Mar 2014 10:57:33 +0000 (10:57 +0000)
31 files changed:
src/lib/audio_content.cc
src/lib/content.cc
src/lib/dcpomatic_time.cc
src/lib/dcpomatic_time.h
src/lib/ffmpeg_content.cc
src/lib/ffmpeg_content.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/ffmpeg_examiner.cc
src/lib/image_content.cc
src/lib/player.cc
src/lib/player.h
src/lib/sndfile_content.cc
src/lib/subrip_content.cc
src/lib/video_content.cc
src/lib/writer.cc
src/wx/film_viewer.cc
src/wx/properties_dialog.cc
src/wx/timeline.cc
test/audio_analysis_test.cc
test/audio_merger_test.cc
test/client_server_test.cc
test/ffmpeg_audio_test.cc
test/ffmpeg_examiner_test.cc
test/ffmpeg_pts_offset.cc
test/ffmpeg_seek_test.cc
test/image_test.cc
test/play_test.cc
test/silence_padding_test.cc
test/subrip_test.cc
test/util_test.cc

index 1def7e5ccf28a8f8ab85c8063d4bd4a17379e209..01d1ecc382ad8b386be9f7c5d0fe45a9b0d51de6 100644 (file)
@@ -147,5 +147,11 @@ AudioContent::audio_analysis_path () const
 string
 AudioContent::technical_summary () const
 {
-       return String::compose ("audio: channels %1, length %2, raw rate %3, out rate %4", audio_channels(), audio_length(), content_audio_frame_rate(), output_audio_frame_rate());
+       return String::compose (
+               "audio: channels %1, length %2, raw rate %3, out rate %4",
+               audio_channels(),
+               audio_length().seconds(),
+               content_audio_frame_rate(),
+               output_audio_frame_rate()
+               );
 }
index 4493c67c0bc240ed545418f7b223abb576626b5d..814d9c1a5c00afc2ade07ed4d70f9b92cc536293 100644 (file)
@@ -96,11 +96,11 @@ Content::Content (shared_ptr<const Film> f, vector<shared_ptr<Content> > c)
        , _change_signals_frequent (false)
 {
        for (size_t i = 0; i < c.size(); ++i) {
-               if (i > 0 && c[i]->trim_start ()) {
+               if (i > 0 && c[i]->trim_start() > DCPTime()) {
                        throw JoinError (_("Only the first piece of content to be joined can have a start trim."));
                }
 
-               if (i < (c.size() - 1) && c[i]->trim_end ()) {
+               if (i < (c.size() - 1) && c[i]->trim_end () > DCPTime()) {
                        throw JoinError (_("Only the last piece of content to be joined can have an end trim."));
                }
 
@@ -201,7 +201,7 @@ Content::clone () const
 string
 Content::technical_summary () const
 {
-       return String::compose ("%1 %2 %3", path_summary(), digest(), position());
+       return String::compose ("%1 %2 %3", path_summary(), digest(), position().seconds());
 }
 
 DCPTime
@@ -219,9 +219,9 @@ Content::identifier () const
        stringstream s;
        
        s << Content::digest()
-         << "_" << position()
-         << "_" << trim_start()
-         << "_" << trim_end();
+         << "_" << position().get()
+         << "_" << trim_start().get()
+         << "_" << trim_end().get();
 
        return s.str ();
 }
index 5344915c0c71c31639629ad58995ff6a3a96c25d..98888646d0a841e26bcb077a426be8ac66e1e8e4 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "dcpomatic_time.h"
 
+using std::ostream;
+
 ContentTime::ContentTime (DCPTime d, FrameRateChange f)
        : Time (rint (d.get() * f.speed_up))
 {
@@ -33,3 +35,17 @@ DCPTime min (DCPTime a, DCPTime b)
 
        return b;
 }
+
+ostream &
+operator<< (ostream& s, ContentTime t)
+{
+       s << "[CONT " << t.get() << " " << t.seconds() << "s]";
+       return s;
+}
+
+ostream &
+operator<< (ostream& s, DCPTime t)
+{
+       s << "[DCP " << t.get() << " " << t.seconds() << "s]";
+       return s;
+}
index 05b4e1a5d7d1d2061fe26327068632e03c79c78b..b19a94ad78d5b817f117cd5b9080c0bf71860208 100644 (file)
@@ -21,6 +21,7 @@
 #define DCPOMATIC_TIME_H
 
 #include <cmath>
+#include <ostream>
 #include <stdint.h>
 #include "frame_rate_change.h"
 
@@ -55,10 +56,6 @@ public:
                return rint (_t * r / HZ);
        }
 
-       operator bool () const {
-               return _t != 0;
-       }
-
 protected:
        friend class dcptime_round_up_test;
        
@@ -109,6 +106,10 @@ public:
                return *this;
        }
 
+       ContentTime operator- () const {
+               return ContentTime (-_t);
+       }
+
        ContentTime operator- (ContentTime const & o) const {
                return ContentTime (_t - o._t);
        }
@@ -118,6 +119,17 @@ public:
                return *this;
        }
 
+       /** Round up to the nearest sampling interval
+        *  at some sampling rate.
+        *  @param r Sampling rate.
+        */
+       ContentTime round_up (int r) {
+               int64_t const n = HZ / r;
+               int64_t const a = _t + n - 1;
+               return ContentTime (a - (a % n));
+       }
+       
+
        static ContentTime from_seconds (double s) {
                return ContentTime (s * HZ);
        }
@@ -128,6 +140,8 @@ public:
        }
 };
 
+std::ostream& operator<< (std::ostream& s, ContentTime t);
+
 class DCPTime : public Time
 {
 public:
@@ -210,5 +224,6 @@ public:
 };
 
 DCPTime min (DCPTime a, DCPTime b);
+std::ostream& operator<< (std::ostream& s, DCPTime t);
 
 #endif
index bd5648ecbc2a6d4166096c289d135562b87ca126..e9be3cc46bfa1c69284f805e2d39c0129de7f0ad 100644 (file)
@@ -147,7 +147,7 @@ FFmpegContent::as_xml (xmlpp::Node* node) const
        }
 
        if (_first_video) {
-               node->add_child("FirstVideo")->add_child_text (lexical_cast<string> (_first_video.get ()));
+               node->add_child("FirstVideo")->add_child_text (lexical_cast<string> (_first_video.get().get()));
        }
 }
 
@@ -162,6 +162,7 @@ FFmpegContent::examine (shared_ptr<Job> job)
        assert (film);
 
        shared_ptr<FFmpegExaminer> examiner (new FFmpegExaminer (shared_from_this ()));
+       take_from_video_examiner (examiner);
 
        ContentTime video_length = examiner->video_length ();
        film->log()->log (String::compose ("Video length obtained from header as %1 frames", video_length.frames (video_frame_rate ())));
@@ -184,8 +185,6 @@ FFmpegContent::examine (shared_ptr<Job> job)
                _first_video = examiner->first_video ();
        }
 
-       take_from_video_examiner (examiner);
-
        signal_changed (ContentProperty::LENGTH);
        signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
        signal_changed (FFmpegContentProperty::SUBTITLE_STREAM);
@@ -227,13 +226,13 @@ FFmpegContent::technical_summary () const
 string
 FFmpegContent::information () const
 {
-       if (video_length() == ContentTime (0) || video_frame_rate() == ContentTime (0)) {
+       if (video_length() == ContentTime (0) || video_frame_rate() == 0) {
                return "";
        }
        
        stringstream s;
        
-       s << String::compose (_("%1 frames; %2 frames per second"), video_length(), video_frame_rate()) << "\n";
+       s << String::compose (_("%1 frames; %2 frames per second"), video_length().frames (video_frame_rate()), video_frame_rate()) << "\n";
        s << VideoContent::information ();
 
        return s.str ();
@@ -363,7 +362,7 @@ FFmpegAudioStream::as_xml (xmlpp::Node* root) const
        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) {
-               root->add_child("FirstAudio")->add_child_text (lexical_cast<string> (first_audio.get ()));
+               root->add_child("FirstAudio")->add_child_text (lexical_cast<string> (first_audio.get().get()));
        }
        mapping.as_xml (root->add_child("Mapping"));
 }
index d93660cd0fa573eb391c0a9f4fdf039f524cc9b6..935d9560de8feaa3bcc6b80cb94d9c2c6fe28cfb 100644 (file)
@@ -87,7 +87,7 @@ public:
        int frame_rate;
        int channels;
        AudioMapping mapping;
-       boost::optional<double> first_audio;
+       boost::optional<ContentTime> first_audio;
 
 private:
        friend class ffmpeg_pts_offset_test;
@@ -181,7 +181,7 @@ public:
        void set_subtitle_stream (boost::shared_ptr<FFmpegSubtitleStream>);
        void set_audio_stream (boost::shared_ptr<FFmpegAudioStream>);
 
-       boost::optional<double> first_video () const {
+       boost::optional<ContentTime> first_video () const {
                boost::mutex::scoped_lock lm (_mutex);
                return _first_video;
        }
@@ -193,7 +193,7 @@ private:
        boost::shared_ptr<FFmpegSubtitleStream> _subtitle_stream;
        std::vector<boost::shared_ptr<FFmpegAudioStream> > _audio_streams;
        boost::shared_ptr<FFmpegAudioStream> _audio_stream;
-       boost::optional<double> _first_video;
+       boost::optional<ContentTime> _first_video;
        /** Video filters that should be used when generating DCPs */
        std::vector<Filter const *> _filters;
 };
index 97251b6c2492a36142f22b1b21f84c91a8e98f2b..8b28a5c13da4ae0e2320c1b323a8429714e5f4a7 100644 (file)
@@ -99,15 +99,9 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
 
        /* Now adjust both so that the video pts starts on a frame */
        if (have_video && have_audio) {
-               double first_video = c->first_video().get() + _pts_offset;
-               double const old_first_video = first_video;
-               
-               /* Round the first video up to a frame boundary */
-               if (fabs (rint (first_video * c->video_frame_rate()) - first_video * c->video_frame_rate()) > 1e-6) {
-                       first_video = ceil (first_video * c->video_frame_rate()) / c->video_frame_rate ();
-               }
-
-               _pts_offset += first_video - old_first_video;
+               ContentTime first_video = c->first_video().get() + _pts_offset;
+               ContentTime const old_first_video = first_video;
+               _pts_offset += first_video.round_up (c->video_frame_rate ()) - old_first_video;
        }
 }
 
@@ -317,7 +311,7 @@ FFmpegDecoder::minimal_run (boost::function<bool (optional<ContentTime>, optiona
                        int finished = 0;
                        r = avcodec_decode_video2 (video_codec_context(), _frame, &finished, &_packet);
                        if (r >= 0 && finished) {
-                               last_video = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base + _pts_offset);
+                               last_video = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset;
                        }
 
                } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, _packet.stream_index)) {
@@ -327,7 +321,7 @@ FFmpegDecoder::minimal_run (boost::function<bool (optional<ContentTime>, optiona
                                int finished;
                                r = avcodec_decode_audio4 (audio_codec_context(), _frame, &finished, &_packet);
                                if (r >= 0 && finished) {
-                                       last_audio = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base + _pts_offset);
+                                       last_audio = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset;
                                }
                                        
                                copy_packet.data += r;
@@ -356,11 +350,12 @@ FFmpegDecoder::seek_final_finished (int n, int done) const
 void
 FFmpegDecoder::seek_and_flush (ContentTime t)
 {
-       int64_t s = (t.seconds() - _pts_offset) / av_q2d (_format_context->streams[_video_stream]->time_base);
+       ContentTime const u = t - _pts_offset;
+       int64_t s = u.seconds() / av_q2d (_format_context->streams[_video_stream]->time_base);
 
        if (_ffmpeg_content->audio_stream ()) {
                s = min (
-                       s, int64_t ((t.seconds() - _pts_offset) / av_q2d (_ffmpeg_content->audio_stream()->stream(_format_context)->time_base))
+                       s, int64_t (u.seconds() / av_q2d (_ffmpeg_content->audio_stream()->stream(_format_context)->time_base))
                        );
        }
 
@@ -441,9 +436,8 @@ FFmpegDecoder::decode_audio_packet ()
                if (frame_finished) {
                        ContentTime const ct = ContentTime::from_seconds (
                                av_frame_get_best_effort_timestamp (_frame) *
-                               av_q2d (_ffmpeg_content->audio_stream()->stream (_format_context)->time_base)
-                               + _pts_offset
-                               );
+                               av_q2d (_ffmpeg_content->audio_stream()->stream (_format_context)->time_base))
+                               + _pts_offset;
                        
                        int const data_size = av_samples_get_buffer_size (
                                0, audio_codec_context()->channels, _frame->nb_samples, audio_sample_format (), 1
@@ -498,7 +492,7 @@ FFmpegDecoder::decode_video_packet ()
                }
                
                if (i->second != AV_NOPTS_VALUE) {
-                       video (image, false, ContentTime::from_seconds (i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset));
+                       video (image, false, ContentTime::from_seconds (i->second * av_q2d (_format_context->streams[_video_stream]->time_base)) + _pts_offset);
                } else {
                        shared_ptr<const Film> film = _film.lock ();
                        assert (film);
@@ -554,14 +548,14 @@ FFmpegDecoder::decode_subtitle_packet ()
                throw DecodeError (_("multi-part subtitles not yet supported"));
        }
                
-       /* Subtitle PTS in seconds (within the source, not taking into account any of the
+       /* Subtitle PTS (within the source, not taking into account any of the
           source that we may have chopped off for the DCP)
        */
-       double const packet_time = (static_cast<double> (sub.pts) / AV_TIME_BASE) + _pts_offset;
+       ContentTime packet_time = ContentTime::from_seconds (static_cast<double> (sub.pts) / AV_TIME_BASE) + _pts_offset;
        
        /* hence start time for this sub */
-       ContentTime const from = ContentTime::from_seconds (packet_time + (double (sub.start_display_time) / 1e3));
-       ContentTime const to = ContentTime::from_seconds (packet_time + (double (sub.end_display_time) / 1e3));
+       ContentTime const from = packet_time + ContentTime::from_seconds (sub.start_display_time / 1e3);
+       ContentTime const to = packet_time + ContentTime::from_seconds (sub.end_display_time / 1e3);
 
        AVSubtitleRect const * rect = sub.rects[0];
 
index ae9eb5084104a7fcaf75557511184b213b21d6f6..8eadb116fd0df60202112c53aae59376e28f2b8f 100644 (file)
@@ -85,5 +85,5 @@ private:
        bool _decode_video;
        bool _decode_audio;
 
-       double _pts_offset;
+       ContentTime _pts_offset;
 };
index 3de62ad079738748f8edaa223faa0a8e562fc663..093df09892082e587f236d91665bd9661d09cb65 100644 (file)
@@ -121,6 +121,7 @@ FFmpegExaminer::video_frame_rate () const
        AVStream* s = _format_context->streams[_video_stream];
 
        if (s->avg_frame_rate.num && s->avg_frame_rate.den) {
+               cout << "here we bitchen well are " << av_q2d (s->avg_frame_rate) << "\n";
                return av_q2d (s->avg_frame_rate);
        }
 
@@ -138,7 +139,7 @@ ContentTime
 FFmpegExaminer::video_length () const
 {
        ContentTime const length = ContentTime::from_seconds (double (_format_context->duration) / AV_TIME_BASE);
-       return ContentTime (1, length.get ());
+       return ContentTime (max (int64_t (1), length.get ()));
 }
 
 string
index db02c6059ed494f553df16c9ea658255b833569d..6a37f30676472c51ec24866179ce5209cc5c2ec8 100644 (file)
@@ -133,7 +133,7 @@ ImageContent::identifier () const
 {
        stringstream s;
        s << VideoContent::identifier ();
-       s << "_" << video_length();
+       s << "_" << video_length().get();
        return s.str ();
 }
 
index 3859915f87520cb69beb9d21d84f2355b8b83919..c2b73cdab86a7ddb3f6d45bb763b5629e598031c 100644 (file)
@@ -126,7 +126,6 @@ Player::pass ()
 
                        dec->set_dcp_times ((*i)->frc, offset);
                        DCPTime const t = dec->dcp_time - offset;
-                       cout << "Peeked " << (*i)->content->paths()[0] << " for " << t << " cf " << ((*i)->content->full_length() - (*i)->content->trim_end ()) << "\n";
                        if (t >= ((*i)->content->full_length() - (*i)->content->trim_end ())) {
                                /* In the end-trimmed part; decoder has nothing else to give us */
                                dec.reset ();
@@ -621,7 +620,7 @@ Player::emit_black ()
 void
 Player::emit_silence (DCPTime most)
 {
-       if (most == 0) {
+       if (most == DCPTime ()) {
                return;
        }
        
@@ -774,7 +773,7 @@ void
 PlayerStatistics::dump (shared_ptr<Log> log) const
 {
        log->log (String::compose ("Video: %1 good %2 skipped %3 black %4 repeat", video.good, video.skip, video.black, video.repeat));
-       log->log (String::compose ("Audio: %1 good %2 skipped %3 silence", audio.good, audio.skip, audio.silence));
+       log->log (String::compose ("Audio: %1 good %2 skipped %3 silence", audio.good, audio.skip, audio.silence.seconds()));
 }
 
 PlayerStatistics const &
index 33ffa80f585aab368d41f178bdc74f691abb297a..6860807b3deb72c7d1cf5866a2bac44e232cb68f 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -85,7 +85,7 @@ public:
                        , skip (0)
                {}
                
-               int64_t silence;
+               DCPTime silence;
                int64_t good;
                int64_t skip;
        } audio;
index f8648107ae709f07da54eb2fa528bdf58e38ca97..1aa7bde618283095d13a69ec2d8193cd293f44e0 100644 (file)
@@ -81,7 +81,7 @@ SndfileContent::information () const
                _("%1 channels, %2kHz, %3 samples"),
                audio_channels(),
                content_audio_frame_rate() / 1000.0,
-               audio_length()
+               audio_length().frames (content_audio_frame_rate ())
                );
        
        return s.str ();
@@ -136,7 +136,7 @@ SndfileContent::as_xml (xmlpp::Node* node) const
        AudioContent::as_xml (node);
 
        node->add_child("AudioChannels")->add_child_text (lexical_cast<string> (audio_channels ()));
-       node->add_child("AudioLength")->add_child_text (lexical_cast<string> (audio_length ()));
+       node->add_child("AudioLength")->add_child_text (lexical_cast<string> (audio_length().get ()));
        node->add_child("AudioFrameRate")->add_child_text (lexical_cast<string> (content_audio_frame_rate ()));
        _audio_mapping.as_xml (node->add_child("AudioMapping"));
 }
index 11cba0f66ed39093f87ecdc5937ef29ad663489d..bf034200d366cd532b09bfc5150e948fbc98a560 100644 (file)
@@ -81,7 +81,7 @@ SubRipContent::as_xml (xmlpp::Node* node) const
        node->add_child("Type")->add_child_text ("SubRip");
        Content::as_xml (node);
        SubtitleContent::as_xml (node);
-       node->add_child("Length")->add_child_text (lexical_cast<string> (_length));
+       node->add_child("Length")->add_child_text (lexical_cast<string> (_length.get ()));
 }
 
 DCPTime
index a03300a6b2310b0a06bfc50153bb2ec56646b796..d6122eb51087fe15cc666a8566aa980c1c9c6326 100644 (file)
@@ -155,7 +155,7 @@ void
 VideoContent::as_xml (xmlpp::Node* node) const
 {
        boost::mutex::scoped_lock lm (_mutex);
-       node->add_child("VideoLength")->add_child_text (lexical_cast<string> (_video_length));
+       node->add_child("VideoLength")->add_child_text (lexical_cast<string> (_video_length.get ()));
        node->add_child("VideoWidth")->add_child_text (lexical_cast<string> (_video_size.width));
        node->add_child("VideoHeight")->add_child_text (lexical_cast<string> (_video_size.height));
        node->add_child("VideoFrameRate")->add_child_text (lexical_cast<string> (_video_frame_rate));
@@ -180,11 +180,13 @@ VideoContent::take_from_video_examiner (shared_ptr<VideoExaminer> d)
        /* These examiner calls could call other content methods which take a lock on the mutex */
        dcp::Size const vs = d->video_size ();
        float const vfr = d->video_frame_rate ();
+       cout << "taking " << vfr << "\n";
        
        {
                boost::mutex::scoped_lock lm (_mutex);
                _video_size = vs;
                _video_frame_rate = vfr;
+               cout << "and then " << _video_frame_rate << "\n";
        }
        
        signal_changed (VideoContentProperty::VIDEO_SIZE);
@@ -317,7 +319,13 @@ VideoContent::set_video_frame_type (VideoFrameType t)
 string
 VideoContent::technical_summary () const
 {
-       return String::compose ("video: length %1, size %2x%3, rate %4", video_length(), video_size().width, video_size().height, video_frame_rate());
+       return String::compose (
+               "video: length %1, size %2x%3, rate %4",
+               video_length().seconds(),
+               video_size().width,
+               video_size().height,
+               video_frame_rate()
+               );
 }
 
 dcp::Size
index 6c63314865dae6f9b760a7f94373d533d13577fa..33b7dd51ed00c04ed754ff7d7653cb5dead9639e 100644 (file)
@@ -292,16 +292,16 @@ try
                        _last_written_frame = qi.frame;
                        _last_written_eyes = qi.eyes;
                        
-                       if (_film->length()) {
-                               shared_ptr<Job> job = _job.lock ();
-                               assert (job);
-                               int64_t total = _film->length().frames (_film->video_frame_rate ());
-                               if (_film->three_d ()) {
-                                       /* _full_written and so on are incremented for each eye, so we need to double the total
-                                          frames to get the correct progress.
-                                       */
-                                       total *= 2;
-                               }
+                       shared_ptr<Job> job = _job.lock ();
+                       assert (job);
+                       int64_t total = _film->length().frames (_film->video_frame_rate ());
+                       if (_film->three_d ()) {
+                               /* _full_written and so on are incremented for each eye, so we need to double the total
+                                  frames to get the correct progress.
+                               */
+                               total *= 2;
+                       }
+                       if (total) {
                                job->set_progress (float (_full_written + _fake_written + _repeat_written) / total);
                        }
                }
index a2c4898382eb67e0c84f7047afa5489fa69c0d12..f426a7c6e9f86c77764b6274586abcb2760655d1 100644 (file)
@@ -176,8 +176,8 @@ FilmViewer::timer ()
 
        DCPTime const len = _film->length ();
 
-       if (len) {
-               int const new_slider_position = 4096 * _player->video_position() / len;
+       if (len.get ()) {
+               int const new_slider_position = 4096 * _player->video_position().get() / len.get();
                if (new_slider_position != _slider->GetValue()) {
                        _slider->SetValue (new_slider_position);
                }
@@ -399,7 +399,7 @@ FilmViewer::back_clicked ()
        */
 
        DCPTime p = _player->video_position() - DCPTime::from_frames (2, _film->video_frame_rate ());
-       if (p < 0) {
+       if (p < DCPTime ()) {
                p = DCPTime ();
        }
        
index bdc5742d8cb4a5bd5b440dafbf019e23fdacdbaf..8c976f53ae7df64c34df2d13dd55e132ae5ba250 100644 (file)
@@ -85,10 +85,11 @@ PropertiesDialog::frames_already_encoded () const
        } catch (boost::thread_interrupted &) {
                return "";
        }
-       
-       if (_film->length()) {
+
+       uint64_t const frames = _film->length().frames (_film->video_frame_rate ());
+       if (frames) {
                /* XXX: encoded_frames() should check which frames have been encoded */
-               u << " (" << (_film->encoded_frames() * 100 / _film->length().frames (_film->video_frame_rate ())) << "%)";
+               u << " (" << (_film->encoded_frames() * 100 / frames) << "%)";
        }
        return u.str ();
 }
index 0e713d1deaf07fc3c726fb1f286dfa8d80d0a6e2..ac03c75dad3ae216388a0fb94486060097f1c652 100644 (file)
@@ -64,9 +64,9 @@ public:
 protected:
        virtual void do_paint (wxGraphicsContext *) = 0;
        
-       int time_x (double t) const
+       int time_x (DCPTime t) const
        {
-               return _timeline.tracks_position().x + t * _timeline.pixels_per_second ();
+               return _timeline.tracks_position().x + t.seconds() * _timeline.pixels_per_second ();
        }
        
        Timeline& _timeline;
@@ -292,14 +292,14 @@ private:
                gc->StrokePath (path);
 
                /* Time in seconds */
-               double t;
-               while ((t * _timeline.pixels_per_second()) < _timeline.width()) {
+               DCPTime t;
+               while ((t.seconds() * _timeline.pixels_per_second()) < _timeline.width()) {
                        wxGraphicsPath path = gc->CreatePath ();
                        path.MoveToPoint (time_x (t), _y - 4);
                        path.AddLineToPoint (time_x (t), _y + 4);
                        gc->StrokePath (path);
 
-                       double tc = t;
+                       double tc = t.seconds ();
                        int const h = tc / 3600;
                        tc -= h * 3600;
                        int const m = tc / 60;
@@ -313,12 +313,12 @@ private:
                        wxDouble str_leading;
                        gc->GetTextExtent (str, &str_width, &str_height, &str_descent, &str_leading);
                        
-                       int const tx = _timeline.x_offset() + t * _timeline.pixels_per_second();
+                       int const tx = _timeline.x_offset() + t.seconds() * _timeline.pixels_per_second();
                        if ((tx + str_width) < _timeline.width()) {
                                gc->DrawText (str, time_x (t), _y + 16);
                        }
                        
-                       t += mark_interval;
+                       t += DCPTime::from_seconds (mark_interval);
                }
        }
 
@@ -475,7 +475,7 @@ void
 Timeline::setup_pixels_per_second ()
 {
        shared_ptr<const Film> film = _film.lock ();
-       if (!film || film->length() == 0) {
+       if (!film || film->length() == DCPTime ()) {
                return;
        }
 
@@ -639,13 +639,13 @@ Timeline::set_position_from_event (wxMouseEvent& ev)
                
                if (!first) {
                        /* Snap if it's close; `close' means within a proportion of the time on the timeline */
-                       if (nearest_distance < (width() / pixels_per_second()) / 32) {
+                       if (nearest_distance < DCPTime::from_seconds ((width() / pixels_per_second()) / 32)) {
                                new_position = nearest_new_position;
                        }
                }
        }
        
-       if (new_position < 0) {
+       if (new_position < DCPTime ()) {
                new_position = DCPTime ();
        }
        
index 77b2aeaf6f9671a1685bf841d357685145a291a8..b94b120564a13af559571323bb102494eba0cc2b 100644 (file)
@@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE (audio_analysis_test)
 
        AudioAnalysis b ("build/test/audio_analysis_test");
        for (int i = 0; i < channels; ++i) {
-               BOOST_CHECK (b.points(i) == points);
+               BOOST_CHECK_EQUAL (b.points(i), points);
                for (int j = 0; j < points; ++j) {
                        AudioPoint p = b.get_point (i, j);
                        BOOST_CHECK_CLOSE (p[AudioPoint::PEAK], random_float (), 1);
index e8af22d2ae56a54b0361fe04ef90e3806c3a7e02..c65c0defdb7665a4e0b335cb984e92eba77390c4 100644 (file)
@@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE (audio_merger_test1)
        TimedAudioBuffers<DCPTime> tb = merger.pull (DCPTime::from_frames (22, frame_rate));
        BOOST_CHECK (tb.audio != shared_ptr<const AudioBuffers> ());
        BOOST_CHECK_EQUAL (tb.audio->frames(), 22);
-       BOOST_CHECK_EQUAL (tb.time, 0);
+       BOOST_CHECK_EQUAL (tb.time, DCPTime ());
 
        /* And they should be a staircase */
        for (int i = 0; i < 22; ++i) {
@@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE (audio_merger_test2)
 
        TimedAudioBuffers<DCPTime> tb = merger.pull (DCPTime::from_frames (9, frame_rate));
        BOOST_CHECK_EQUAL (tb.audio->frames(), 9);
-       BOOST_CHECK_EQUAL (tb.time, 0);
+       BOOST_CHECK_EQUAL (tb.time, DCPTime ());
        
        for (int i = 0; i < 9; ++i) {
                BOOST_CHECK_EQUAL (tb.audio->data()[0][i], 0);
@@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE (audio_merger_test2)
 
        /* That flush should give us 64 samples at 9 */
        BOOST_CHECK_EQUAL (tb.audio->frames(), 64);
-       BOOST_CHECK_EQUAL (tb.time, 9);
+       BOOST_CHECK_EQUAL (tb.time, DCPTime::from_frames (9, frame_rate));
        
        /* Check the sample values */
        for (int i = 0; i < 64; ++i) {
index a80297ec690b132c041aa9d643f882c6457ff168..54bbd520f8dd9c8d37ca2d1b30efd00cf2bca2f4 100644 (file)
@@ -36,7 +36,7 @@ do_remote_encode (shared_ptr<DCPVideoFrame> frame, ServerDescription description
        BOOST_CHECK (remotely_encoded);
        
        BOOST_CHECK_EQUAL (locally_encoded->size(), remotely_encoded->size());
-       BOOST_CHECK (memcmp (locally_encoded->data(), remotely_encoded->data(), locally_encoded->size()) == 0);
+       BOOST_CHECK_EQUAL (memcmp (locally_encoded->data(), remotely_encoded->data(), locally_encoded->size()), 0);
 }
 
 BOOST_AUTO_TEST_CASE (client_server_test)
index 8942558791a8e10b07eee8a64d783651a8f00960..48422259c7d272c7df160b1b6daa6d5b6bbd5139 100644 (file)
@@ -65,7 +65,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_audio_test)
 
        shared_ptr<const dcp::ReelSoundAsset> sound_asset = check.cpls().front()->reels().front()->main_sound ();
        BOOST_CHECK (sound_asset);
-       BOOST_CHECK (sound_asset->mxf()->channels () == 6);
+       BOOST_CHECK_EQUAL (sound_asset->mxf()->channels (), 6);
 
        /* Sample index in the DCP */
        int n = 0;
index a3b9bb4f6506793186b1aff886f68f67c07d6662..93a913870f81a108e1dfe46b135e16a912eeb5ab 100644 (file)
@@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_examiner_test)
        shared_ptr<FFmpegContent> content (new FFmpegContent (film, "test/data/count300bd24.m2ts"));
        shared_ptr<FFmpegExaminer> examiner (new FFmpegExaminer (content));
 
-       BOOST_CHECK_EQUAL (examiner->first_video().get(), 600);
+       BOOST_CHECK_EQUAL (examiner->first_video().get(), ContentTime (600));
        BOOST_CHECK_EQUAL (examiner->audio_streams().size(), 1);
-       BOOST_CHECK_EQUAL (examiner->audio_streams()[0]->first_audio.get(), 600);
+       BOOST_CHECK_EQUAL (examiner->audio_streams()[0]->first_audio.get(), ContentTime (600));
 }
index 53303f1543bcda650274f7d2736a1668a7691af8..4a9a57b402295e52d6668fec3b2e1ef92ed06109 100644 (file)
@@ -34,43 +34,43 @@ BOOST_AUTO_TEST_CASE (ffmpeg_pts_offset_test)
 
        {
                /* Sound == video so no offset required */
-               content->_first_video = 0;
-               content->_audio_stream->first_audio = 0;
+               content->_first_video = ContentTime ();
+               content->_audio_stream->first_audio = ContentTime ();
                FFmpegDecoder decoder (film, content, true, true);
-               BOOST_CHECK_EQUAL (decoder._pts_offset, 0);
+               BOOST_CHECK_EQUAL (decoder._pts_offset, ContentTime ());
        }
 
        {
                /* Common offset should be removed */
-               content->_first_video = 600;
-               content->_audio_stream->first_audio = 600;
+               content->_first_video = ContentTime::from_seconds (600);
+               content->_audio_stream->first_audio = ContentTime::from_seconds (600);
                FFmpegDecoder decoder (film, content, true, true);
-               BOOST_CHECK_EQUAL (decoder._pts_offset, -600);
+               BOOST_CHECK_EQUAL (decoder._pts_offset, ContentTime::from_seconds (-600));
        }
 
        {
                /* Video is on a frame boundary */
-               content->_first_video = 1.0 / 24.0;
-               content->_audio_stream->first_audio = 0;
+               content->_first_video = ContentTime::from_frames (1, 24);
+               content->_audio_stream->first_audio = ContentTime ();
                FFmpegDecoder decoder (film, content, true, true);
-               BOOST_CHECK_EQUAL (decoder._pts_offset, 0);
+               BOOST_CHECK_EQUAL (decoder._pts_offset, ContentTime ());
        }
 
        {
                /* Video is off a frame boundary */
                double const frame = 1.0 / 24.0;
-               content->_first_video = frame + 0.0215;
-               content->_audio_stream->first_audio = 0;
+               content->_first_video = ContentTime::from_seconds (frame + 0.0215);
+               content->_audio_stream->first_audio = ContentTime ();
                FFmpegDecoder decoder (film, content, true, true);
-               BOOST_CHECK_CLOSE (decoder._pts_offset, (frame - 0.0215), 0.00001);
+               BOOST_CHECK_CLOSE (decoder._pts_offset.seconds(), (frame - 0.0215), 0.00001);
        }
 
        {
                /* Video is off a frame boundary and both have a common offset */
                double const frame = 1.0 / 24.0;
-               content->_first_video = frame + 0.0215 + 4.1;
-               content->_audio_stream->first_audio = 4.1;
+               content->_first_video = ContentTime::from_seconds (frame + 0.0215 + 4.1);
+               content->_audio_stream->first_audio = ContentTime::from_seconds (4.1);
                FFmpegDecoder decoder (film, content, true, true);
-               BOOST_CHECK_EQUAL (decoder._pts_offset, (frame - 0.0215) - 4.1);
+               BOOST_CHECK_EQUAL (decoder._pts_offset.seconds(), (frame - 0.0215) - 4.1);
        }
 }
index ccc59e0642c7a10bbf2af85b483c5d0065e3e85b..c25a071deedb9fd082cfe8919ab4448baa5c50a3 100644 (file)
@@ -62,7 +62,7 @@ static string
 print_time (DCPTime t, float fps)
 {
        stringstream s;
-       s << t << " " << t.seconds() << "s " << t.frames (fps) << "f";
+       s << t.seconds() << "s " << t.frames (fps) << "f";
        return s.str ();
 }
 
@@ -90,8 +90,8 @@ check (shared_ptr<Player> p, DCPTime t)
        BOOST_CHECK (first_video.get() >= t);
        BOOST_CHECK (first_audio.get() >= t);
        /* And should be rounded to frame boundaries */
-       BOOST_CHECK (first_video.get() == first_video.get().round_up (film->video_frame_rate()));
-       BOOST_CHECK (first_audio.get() == first_audio.get().round_up (film->audio_frame_rate()));
+       BOOST_CHECK_EQUAL (first_video.get(), first_video.get().round_up (film->video_frame_rate()));
+       BOOST_CHECK_EQUAL (first_audio.get(), first_audio.get().round_up (film->audio_frame_rate()));
 }
 
 /* Test basic seeking */
index 622a9e4db28544e82c051eba6d4026bb72fb7e9e..f876c8f65fc08c1e9d12b5758c982a7abe93f18e 100644 (file)
@@ -50,9 +50,9 @@ BOOST_AUTO_TEST_CASE (aligned_image_test)
        BOOST_CHECK (t->data() != s->data());
        BOOST_CHECK (t->data()[0] != s->data()[0]);
        BOOST_CHECK (t->line_size() != s->line_size());
-       BOOST_CHECK (t->line_size()[0] == s->line_size()[0]);
+       BOOST_CHECK_EQUAL (t->line_size()[0], s->line_size()[0]);
        BOOST_CHECK (t->stride() != s->stride());
-       BOOST_CHECK (t->stride()[0] == s->stride()[0]);
+       BOOST_CHECK_EQUAL (t->stride()[0], s->stride()[0]);
 
        /* assignment operator */
        Image* u = new Image (PIX_FMT_YUV422P, dcp::Size (150, 150), false);
@@ -67,9 +67,9 @@ BOOST_AUTO_TEST_CASE (aligned_image_test)
        BOOST_CHECK (u->data() != s->data());
        BOOST_CHECK (u->data()[0] != s->data()[0]);
        BOOST_CHECK (u->line_size() != s->line_size());
-       BOOST_CHECK (u->line_size()[0] == s->line_size()[0]);
+       BOOST_CHECK_EQUAL (u->line_size()[0], s->line_size()[0]);
        BOOST_CHECK (u->stride() != s->stride());
-       BOOST_CHECK (u->stride()[0] == s->stride()[0]);
+       BOOST_CHECK_EQUAL (u->stride()[0], s->stride()[0]);
 
        delete s;
        delete t;
@@ -99,9 +99,9 @@ BOOST_AUTO_TEST_CASE (compact_image_test)
        BOOST_CHECK (t->data() != s->data());
        BOOST_CHECK (t->data()[0] != s->data()[0]);
        BOOST_CHECK (t->line_size() != s->line_size());
-       BOOST_CHECK (t->line_size()[0] == s->line_size()[0]);
+       BOOST_CHECK_EQUAL (t->line_size()[0], s->line_size()[0]);
        BOOST_CHECK (t->stride() != s->stride());
-       BOOST_CHECK (t->stride()[0] == s->stride()[0]);
+       BOOST_CHECK_EQUAL (t->stride()[0], s->stride()[0]);
 
        /* assignment operator */
        Image* u = new Image (PIX_FMT_YUV422P, dcp::Size (150, 150), true);
@@ -116,9 +116,9 @@ BOOST_AUTO_TEST_CASE (compact_image_test)
        BOOST_CHECK (u->data() != s->data());
        BOOST_CHECK (u->data()[0] != s->data()[0]);
        BOOST_CHECK (u->line_size() != s->line_size());
-       BOOST_CHECK (u->line_size()[0] == s->line_size()[0]);
+       BOOST_CHECK_EQUAL (u->line_size()[0], s->line_size()[0]);
        BOOST_CHECK (u->stride() != s->stride());
-       BOOST_CHECK (u->stride()[0] == s->stride()[0]);
+       BOOST_CHECK_EQUAL (u->stride()[0], s->stride()[0]);
 
        delete s;
        delete t;
index 5ffc55a8ee8e3b7488044a1319b3da2137d20c8a..690b042d8c32722f78e1c75e5c800e22cc685251 100644 (file)
@@ -89,18 +89,18 @@ BOOST_AUTO_TEST_CASE (play_test)
        film->examine_and_add_content (A);
        wait_for_jobs ();
 
-       BOOST_CHECK_EQUAL (A->video_length(), 16);
+       BOOST_CHECK_EQUAL (A->video_length().frames (24), 16);
 
        shared_ptr<FFmpegContent> B (new FFmpegContent (film, "test/data/red_30.mp4"));
        film->examine_and_add_content (B);
        wait_for_jobs ();
 
-       BOOST_CHECK_EQUAL (B->video_length(), 16);
+       BOOST_CHECK_EQUAL (B->video_length().frames (30), 16);
        
        /* Film should have been set to 25fps */
        BOOST_CHECK_EQUAL (film->video_frame_rate(), 25);
 
-       BOOST_CHECK_EQUAL (A->position(), 0);
+       BOOST_CHECK_EQUAL (A->position(), DCPTime ());
        /* A is 16 frames long at 25 fps */
        BOOST_CHECK_EQUAL (B->position(), DCPTime::from_frames (16, 25));
 
index bfc225f546be88e6a84bcd39ebe44d0fe96a6515..e4472ad4fef042f52f4822e56f5b82b2290a2009 100644 (file)
@@ -58,7 +58,7 @@ static void test_silence_padding (int channels)
 
        shared_ptr<const dcp::ReelSoundAsset> sound_asset = check.cpls().front()->reels().front()->main_sound ();
        BOOST_CHECK (sound_asset);
-       BOOST_CHECK (sound_asset->mxf()->channels () == channels);
+       BOOST_CHECK_EQUAL (sound_asset->mxf()->channels (), channels);
 
        /* Sample index in the DCP */
        int n = 0;
index d8c2d75de0da539c4d8a2fc66fe0c1aed63fe8bf..315c0cf1e569deb02d1fd5640e18ca3fc8c2b29a 100644 (file)
@@ -130,45 +130,45 @@ BOOST_AUTO_TEST_CASE (subrip_parse_test)
        vector<SubRipSubtitle>::const_iterator i = s._subtitles.begin();
 
        BOOST_CHECK (i != s._subtitles.end ());
-       BOOST_CHECK_EQUAL (i->from, DCPTime::from_seconds ((1 * 60) + 49.200));
-       BOOST_CHECK_EQUAL (i->to, DCPTime::from_seconds ((1 * 60) + 52.351));
+       BOOST_CHECK_EQUAL (i->from, ContentTime::from_seconds ((1 * 60) + 49.200));
+       BOOST_CHECK_EQUAL (i->to, ContentTime::from_seconds ((1 * 60) + 52.351));
        BOOST_CHECK_EQUAL (i->pieces.size(), 1);
        BOOST_CHECK_EQUAL (i->pieces.front().text, "This is a subtitle, and it goes over two lines.");
 
        ++i;
        BOOST_CHECK (i != s._subtitles.end ());
-       BOOST_CHECK_EQUAL (i->from, DCPTime::from_seconds ((1 * 60) + 52.440));
-       BOOST_CHECK_EQUAL (i->to, DCPTime::from_seconds ((1 * 60) + 54.351));
+       BOOST_CHECK_EQUAL (i->from, ContentTime::from_seconds ((1 * 60) + 52.440));
+       BOOST_CHECK_EQUAL (i->to, ContentTime::from_seconds ((1 * 60) + 54.351));
        BOOST_CHECK_EQUAL (i->pieces.size(), 1);
        BOOST_CHECK_EQUAL (i->pieces.front().text, "We have emboldened this");
        BOOST_CHECK_EQUAL (i->pieces.front().bold, true);
 
        ++i;
        BOOST_CHECK (i != s._subtitles.end ());
-       BOOST_CHECK_EQUAL (i->from, DCPTime::from_seconds ((1 * 60) + 54.440));
-       BOOST_CHECK_EQUAL (i->to, DCPTime::from_seconds ((1 * 60) + 56.590));
+       BOOST_CHECK_EQUAL (i->from, ContentTime::from_seconds ((1 * 60) + 54.440));
+       BOOST_CHECK_EQUAL (i->to, ContentTime::from_seconds ((1 * 60) + 56.590));
        BOOST_CHECK_EQUAL (i->pieces.size(), 1);
        BOOST_CHECK_EQUAL (i->pieces.front().text, "And italicised this.");
        BOOST_CHECK_EQUAL (i->pieces.front().italic, true);
 
        ++i;
        BOOST_CHECK (i != s._subtitles.end ());
-       BOOST_CHECK_EQUAL (i->from, DCPTime::from_seconds ((1 * 60) + 56.680));
-       BOOST_CHECK_EQUAL (i->to, DCPTime::from_seconds ((1 * 60) + 58.955));
+       BOOST_CHECK_EQUAL (i->from, ContentTime::from_seconds ((1 * 60) + 56.680));
+       BOOST_CHECK_EQUAL (i->to, ContentTime::from_seconds ((1 * 60) + 58.955));
        BOOST_CHECK_EQUAL (i->pieces.size(), 1);
        BOOST_CHECK_EQUAL (i->pieces.front().text, "Shall I compare thee to a summers' day?");
 
        ++i;
        BOOST_CHECK (i != s._subtitles.end ());
-       BOOST_CHECK_EQUAL (i->from, DCPTime::from_seconds ((2 * 60) + 0.840));
-       BOOST_CHECK_EQUAL (i->to, DCPTime::from_seconds ((2 * 60) + 3.400));
+       BOOST_CHECK_EQUAL (i->from, ContentTime::from_seconds ((2 * 60) + 0.840));
+       BOOST_CHECK_EQUAL (i->to, ContentTime::from_seconds ((2 * 60) + 3.400));
        BOOST_CHECK_EQUAL (i->pieces.size(), 1);
        BOOST_CHECK_EQUAL (i->pieces.front().text, "Is this a dagger I see before me?");
 
        ++i;
        BOOST_CHECK (i != s._subtitles.end ());
-       BOOST_CHECK_EQUAL (i->from, DCPTime::from_seconds ((3 * 60) + 54.560));
-       BOOST_CHECK_EQUAL (i->to, DCPTime::from_seconds ((3 * 60) + 56.471));
+       BOOST_CHECK_EQUAL (i->from, ContentTime::from_seconds ((3 * 60) + 54.560));
+       BOOST_CHECK_EQUAL (i->to, ContentTime::from_seconds ((3 * 60) + 56.471));
        BOOST_CHECK_EQUAL (i->pieces.size(), 1);
        BOOST_CHECK_EQUAL (i->pieces.front().text, "Hello world.");
 
index 3373bf86b59e468bed2b97736987f858cd477b54..25b8140044afadbab3dd0f19d9e5cfcaeaf35a66 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -57,15 +57,15 @@ BOOST_AUTO_TEST_CASE (md5_digest_test)
 /* Straightforward test of DCPTime::round_up */
 BOOST_AUTO_TEST_CASE (dcptime_round_up_test)
 {
-       BOOST_CHECK_EQUAL (DCPTime (0).round_up (DCPTime::HZ / 2), 0);
-       BOOST_CHECK_EQUAL (DCPTime (1).round_up (DCPTime::HZ / 2), 2);
-       BOOST_CHECK_EQUAL (DCPTime (2).round_up (DCPTime::HZ / 2), 2);
-       BOOST_CHECK_EQUAL (DCPTime (3).round_up (DCPTime::HZ / 2), 4);
+       BOOST_CHECK_EQUAL (DCPTime (0).round_up (DCPTime::HZ / 2), DCPTime (0));
+       BOOST_CHECK_EQUAL (DCPTime (1).round_up (DCPTime::HZ / 2), DCPTime (2));
+       BOOST_CHECK_EQUAL (DCPTime (2).round_up (DCPTime::HZ / 2), DCPTime (2));
+       BOOST_CHECK_EQUAL (DCPTime (3).round_up (DCPTime::HZ / 2), DCPTime (4));
        
-       BOOST_CHECK_EQUAL (DCPTime (0).round_up (DCPTime::HZ / 42), 0);
-       BOOST_CHECK_EQUAL (DCPTime (1).round_up (DCPTime::HZ / 42), 42);
-       BOOST_CHECK_EQUAL (DCPTime (42).round_up (DCPTime::HZ / 42), 42);
-       BOOST_CHECK_EQUAL (DCPTime (43).round_up (DCPTime::HZ / 42), 84);
+       BOOST_CHECK_EQUAL (DCPTime (0).round_up (DCPTime::HZ / 42), DCPTime (0));
+       BOOST_CHECK_EQUAL (DCPTime (1).round_up (DCPTime::HZ / 42), DCPTime (42));
+       BOOST_CHECK_EQUAL (DCPTime (42).round_up (DCPTime::HZ / 42), DCPTime (42));
+       BOOST_CHECK_EQUAL (DCPTime (43).round_up (DCPTime::HZ / 42), DCPTime (84));
 }