1 /*
2    mkvmerge -- utility for splicing together matroska files
3    from component media subtypes
4 
5    Distributed under the GPL v2
6    see the file COPYING for details
7    or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8 
9    Written by Moritz Bunkus <moritz@bunkus.org>.
10 */
11 
12 #include "common/common_pch.h"
13 
14 #include "common/debugging.h"
15 #include "common/frame_timing.h"
16 
17 namespace mtx::frame_timing {
18 
19 std::vector<common_frame_rate_t> g_common_frame_rates{
20   { 1'000'000'000ll         /    120, {    120,     1 } }, // 120 fps
21   { 1'000'000'000ll         /    100, {    100,     1 } }, // 100 fps
22   { 1'000'000'000ll         /     50, {     50,     1 } }, //  50 fps
23   { 1'000'000'000ll         /     48, {     48,     1 } }, //  48 fps
24   { 1'000'000'000ll         /     24, {     24,     1 } }, //  24 fps
25   { 1'000'000'000ll         /     25, {     25,     1 } }, //  25 fps
26   { 1'000'000'000ll         /     60, {     60,     1 } }, //  60 fps
27   { 1'000'000'000ll         /     30, {     30,     1 } }, //  30 fps
28   { 1'000'000'000ll * 1'001 / 48'000, { 48'000, 1'001 } }, //  47.952 fps
29   { 1'000'000'000ll * 1'001 / 24'000, { 24'000, 1'001 } }, //  23.976 fps
30   { 1'000'000'000ll * 1'001 / 50'000, { 50'000, 1'001 } }, //  24.975 frames per second telecined PAL
31   { 1'000'000'000ll * 1'001 / 60'000, { 60'000, 1'001 } }, //  59.94 fps
32   { 1'000'000'000ll * 1'001 / 30'000, { 30'000, 1'001 } }, //  29.97 fps
33 };
34 
35 mtx_mp_rational_t
determine_frame_rate(int64_t duration,int64_t max_difference)36 determine_frame_rate(int64_t duration,
37                      int64_t max_difference) {
38   static debugging_option_c s_debug{"determine_frame_rate|fix_bitstream_timing_info"};
39 
40   // search in the common FPS list
41   using common_frame_rate_diff_t = std::pair<int64_t, common_frame_rate_t>;
42   auto potentials = std::vector<common_frame_rate_diff_t>{};
43 
44   for (auto const &common_frame_rate : g_common_frame_rates) {
45     auto difference = std::abs(duration - common_frame_rate.duration);
46     if (difference < max_difference)
47       potentials.emplace_back(difference, common_frame_rate);
48   }
49 
50   if (potentials.empty()) {
51     mxdebug_if(s_debug, fmt::format("determine_frame_rate: duration {0} max_difference {1}: no match found\n", duration, max_difference));
52     return {};
53   }
54 
55   std::sort(potentials.begin(), potentials.end(), [](auto const &a, auto const &b) {
56     return a.first < b.first;
57   });
58 
59   mxdebug_if(s_debug,
60              fmt::format("determine_frame_rate: duration {0} max_difference {1}: {2} match(es) found returning {3} Δ {4}\n",
61                          duration, max_difference, potentials.size(), potentials[0].second.frame_rate, potentials[0].first));
62 
63   return potentials[0].second.frame_rate;
64 }
65 
66 }
67