Fix rounding of timecodes in at least some cases (#323).
authorCarl Hetherington <cth@carlh.net>
Mon, 3 Mar 2014 12:38:30 +0000 (12:38 +0000)
committerCarl Hetherington <cth@carlh.net>
Mon, 3 Mar 2014 12:38:30 +0000 (12:38 +0000)
Reported-by: GĂ©rald Maruccia
ChangeLog
src/lib/film.cc
src/lib/sndfile_content.cc
src/lib/util.cc
src/lib/util.h
src/wx/timecode.cc
test/util_test.cc

index 2712fc265839c1d3148761d060dd97df49ebf02d..00df090c70e45ef03eef8204e797cc06c872d073 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2014-03-03  Carl Hetherington  <cth@carlh.net>
 
+       * Fix rounding of timecodes in at least some cases (#323).
+
        * Try to prevent OS X from sleeping during DCP encode.
 
 2014-02-26  Carl Hetherington  <cth@carlh.net>
index 1d07ec77f4a0ff50ebc105970709cde687c29099..13481045200ac26be456979fa5fab70e8d8b40f0 100644 (file)
@@ -900,25 +900,25 @@ Film::playlist_changed ()
 OutputAudioFrame
 Film::time_to_audio_frames (Time t) const
 {
-       return t * audio_frame_rate () / TIME_HZ;
+       return divide_with_round (t * audio_frame_rate (), TIME_HZ);
 }
 
 OutputVideoFrame
 Film::time_to_video_frames (Time t) const
 {
-       return t * video_frame_rate () / TIME_HZ;
+       return divide_with_round (t * video_frame_rate (), TIME_HZ);
 }
 
 Time
 Film::audio_frames_to_time (OutputAudioFrame f) const
 {
-       return f * TIME_HZ / audio_frame_rate ();
+       return divide_with_round (f * TIME_HZ, audio_frame_rate ());
 }
 
 Time
 Film::video_frames_to_time (OutputVideoFrame f) const
 {
-       return f * TIME_HZ / video_frame_rate ();
+       return divide_with_round (f * TIME_HZ, video_frame_rate ());
 }
 
 OutputAudioFrame
index 796229777f86374a05b60e0eb11f1bb0c9c34ba5..98171a8433ec768fda8ce9bd6bed99ebd8fe9d9f 100644 (file)
@@ -147,7 +147,7 @@ SndfileContent::full_length () const
        shared_ptr<const Film> film = _film.lock ();
        assert (film);
 
-       OutputAudioFrame const len = audio_length() * output_audio_frame_rate() / content_audio_frame_rate ();
+       OutputAudioFrame const len = divide_with_round (audio_length() * output_audio_frame_rate(), content_audio_frame_rate ());
        
        /* XXX: this depends on whether, alongside this audio, we are running video slower or faster than
           it should be.  The calculation above works out the output audio frames assuming that we are just
index 25fbc130b1be445a3e71df42459f4433970568e1..f604cd10a7830c0e9b0ff69540530233bf2ea926 100644 (file)
@@ -1016,3 +1016,13 @@ entities_to_text (string e)
        boost::algorithm::replace_all (e, "%2F", "/");
        return e;
 }
+
+int64_t
+divide_with_round (int64_t a, int64_t b)
+{
+       if (a % b >= (b / 2)) {
+               return (a + b - 1) / b;
+       } else {
+               return a / b;
+       }
+}
index ef29cc08f27f3ff411d74904b99632d70548cda1..fc17dc9443c920b2dd084c30eba7ca41273e3f69 100644 (file)
@@ -123,6 +123,7 @@ extern std::string get_required_string (std::multimap<std::string, std::string>
 extern int get_optional_int (std::multimap<std::string, std::string> const & kv, std::string k);
 extern std::string get_optional_string (std::multimap<std::string, std::string> const & kv, std::string k);
 extern void* wrapped_av_malloc (size_t);
+extern int64_t divide_with_round (int64_t a, int64_t b);
 
 /** @class Socket
  *  @brief A class to wrap a boost::asio::ip::tcp::socket with some things
index 033bd2bd01e97f29965829c8c28c20bd37fa2a3b..ef0ced428e35a0f868591166b654bd93e810bb3d 100644 (file)
@@ -91,7 +91,7 @@ Timecode::set (Time t, int fps)
        t -= m * 60 * TIME_HZ;
        int const s = t / TIME_HZ;
        t -= s * TIME_HZ;
-       int const f = t * fps / TIME_HZ;
+       int const f = divide_with_round (t * fps, TIME_HZ);
 
        checked_set (_hours, lexical_cast<string> (h));
        checked_set (_minutes, lexical_cast<string> (m));
index 4dccb49c6c1d95302fb031794b90d1ba97217357..750023d9f1a689bb4414706b66c352a4b6cda2d8 100644 (file)
@@ -25,7 +25,7 @@ using std::string;
 using std::vector;
 using boost::shared_ptr;
 
-BOOST_AUTO_TEST_CASE (util_test)
+BOOST_AUTO_TEST_CASE (split_at_spaces_considering_quotes_test)
 {
        string t = "Hello this is a string \"with quotes\" and indeed without them";
        vector<string> b = split_at_spaces_considering_quotes (t);
@@ -53,3 +53,16 @@ BOOST_AUTO_TEST_CASE (md5_digest_test)
        p.push_back ("foobar");
        BOOST_CHECK_THROW (md5_digest (p, shared_ptr<Job> ()), std::runtime_error);
 }
+
+BOOST_AUTO_TEST_CASE (divide_with_round_test)
+{
+       BOOST_CHECK_EQUAL (divide_with_round (0, 4), 0);
+       BOOST_CHECK_EQUAL (divide_with_round (1, 4), 0);
+       BOOST_CHECK_EQUAL (divide_with_round (2, 4), 1);
+       BOOST_CHECK_EQUAL (divide_with_round (3, 4), 1);
+       BOOST_CHECK_EQUAL (divide_with_round (4, 4), 1);
+       BOOST_CHECK_EQUAL (divide_with_round (5, 4), 1);
+       BOOST_CHECK_EQUAL (divide_with_round (6, 4), 2);
+
+       BOOST_CHECK_EQUAL (divide_with_round (1000, 500), 2);
+}