From a2e3a20a441e604550f0036ca198d5d2122e16a7 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 3 Mar 2014 12:38:30 +0000 Subject: [PATCH] Fix rounding of timecodes in at least some cases (#323). MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Reported-by: Gérald Maruccia --- ChangeLog | 2 ++ src/lib/film.cc | 8 ++++---- src/lib/sndfile_content.cc | 2 +- src/lib/util.cc | 10 ++++++++++ src/lib/util.h | 1 + src/wx/timecode.cc | 2 +- test/util_test.cc | 15 ++++++++++++++- 7 files changed, 33 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2712fc265..00df090c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2014-03-03 Carl Hetherington + * 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 diff --git a/src/lib/film.cc b/src/lib/film.cc index 1d07ec77f..134810452 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -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 diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc index 796229777..98171a843 100644 --- a/src/lib/sndfile_content.cc +++ b/src/lib/sndfile_content.cc @@ -147,7 +147,7 @@ SndfileContent::full_length () const shared_ptr 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 diff --git a/src/lib/util.cc b/src/lib/util.cc index 25fbc130b..f604cd10a 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -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; + } +} diff --git a/src/lib/util.h b/src/lib/util.h index ef29cc08f..fc17dc944 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -123,6 +123,7 @@ extern std::string get_required_string (std::multimap extern int get_optional_int (std::multimap const & kv, std::string k); extern std::string get_optional_string (std::multimap 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 diff --git a/src/wx/timecode.cc b/src/wx/timecode.cc index 033bd2bd0..ef0ced428 100644 --- a/src/wx/timecode.cc +++ b/src/wx/timecode.cc @@ -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 (h)); checked_set (_minutes, lexical_cast (m)); diff --git a/test/util_test.cc b/test/util_test.cc index 4dccb49c6..750023d9f 100644 --- a/test/util_test.cc +++ b/test/util_test.cc @@ -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 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 ()), 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); +} -- 2.30.2