summaryrefslogtreecommitdiff
path: root/src/lib/util.cc
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-01-16 23:36:16 +0000
committerCarl Hetherington <cth@carlh.net>2013-01-16 23:36:16 +0000
commite9ee53e42d7f8bbcd2a454ee9de5f3e66ec06b03 (patch)
tree10aaec3604bf0a8770fea1ffd322d82714a31c51 /src/lib/util.cc
parentc7292767fe4935da750423461a41224b3e0a8e37 (diff)
Add some tests and hopefully clarify the DCPFrameRate class.
Diffstat (limited to 'src/lib/util.cc')
-rw-r--r--src/lib/util.cc89
1 files changed, 68 insertions, 21 deletions
diff --git a/src/lib/util.cc b/src/lib/util.cc
index 4228ce6cf..b500ddc2f 100644
--- a/src/lib/util.cc
+++ b/src/lib/util.cc
@@ -26,6 +26,7 @@
#include <iomanip>
#include <iostream>
#include <fstream>
+#include <climits>
#ifdef DVDOMATIC_POSIX
#include <execinfo.h>
#include <cxxabi.h>
@@ -58,6 +59,7 @@ extern "C" {
#include "dcp_content_type.h"
#include "filter.h"
#include "sound_processor.h"
+#include "config.h"
using namespace std;
using namespace boost;
@@ -356,29 +358,74 @@ static bool about_equal (float a, float b)
return (fabs (a - b) < 1e-4);
}
+class FrameRateCandidate
+{
+public:
+ FrameRateCandidate (float source_, int dcp_)
+ : source (source_)
+ , dcp (dcp_)
+ {}
+
+ bool skip () const {
+ return !about_equal (source, dcp) && source > dcp;
+ }
+
+ bool repeat () const {
+ return !about_equal (source, dcp) && source < dcp;
+ }
+
+ float source;
+ int dcp;
+};
+
/** @param fps Arbitrary source frames-per-second value */
-DCPFrameRate::DCPFrameRate (float fps)
- : frames_per_second (rint (fps))
- , skip (false)
- , repeat (false)
- , run_fast (false)
-{
- if (about_equal (fps, 50)) {
- /* XXX: not sure about this; just run at 50?
- Ring Peter Jackson.
- */
- frames_per_second = 25;
- skip = true;
- } else if (fps >= (27.5 / 2) && fps <= (32.5 / 2)) {
- frames_per_second = 30;
- repeat = true;
- } else if (fps >= (24.5 / 2) && fps <= (27.5 / 2)) {
- frames_per_second = 25;
- repeat = true;
- } else if (fps >= (20 / 2) && fps <= (24.5 / 2)) {
- frames_per_second = 24;
- repeat = true;
+/** XXX: this could be slow-ish */
+DCPFrameRate::DCPFrameRate (float source_fps)
+{
+ list<int> const allowed_dcp_frame_rates = Config::instance()->allowed_dcp_frame_rates ();
+
+ /* Work out what rates we could manage, including those achieved by using skip / repeat. */
+ list<FrameRateCandidate> candidates;
+
+ /* Start with the ones without skip / repeat so they will get matched in preference to skipped/repeated ones */
+ for (list<int>::const_iterator i = allowed_dcp_frame_rates.begin(); i != allowed_dcp_frame_rates.end(); ++i) {
+ candidates.push_back (FrameRateCandidate (*i, *i));
}
+
+ /* Then the skip/repeat ones */
+ for (list<int>::const_iterator i = allowed_dcp_frame_rates.begin(); i != allowed_dcp_frame_rates.end(); ++i) {
+ candidates.push_back (FrameRateCandidate (float (*i) / 2, *i));
+ candidates.push_back (FrameRateCandidate (float (*i) * 2, *i));
+ }
+
+ /* Pick the best one, bailing early if we hit an exact match */
+ float error = numeric_limits<float>::max ();
+ boost::optional<FrameRateCandidate> best;
+ list<FrameRateCandidate>::iterator i = candidates.begin();
+ while (i != candidates.end()) {
+
+ if (about_equal (i->source, source_fps)) {
+ best = *i;
+ break;
+ }
+
+ float const e = fabs (i->source - source_fps);
+ if (e < error) {
+ error = e;
+ best = *i;
+ }
+
+ ++i;
+ }
+
+ if (!best) {
+ throw EncodeError ("cannot find a suitable DCP frame rate for this source");
+ }
+
+ frames_per_second = best->dcp;
+ skip = best->skip ();
+ repeat = best->repeat ();
+ change_speed = !about_equal (source_fps * factor(), frames_per_second);
}
/** @param An arbitrary sampling rate.