Merge branch 'resample-drop-frame'
[dcpomatic.git] / src / lib / format.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /** @file src/format.cc
21  *  @brief Class to describe a format (aspect ratio) that a Film should
22  *  be shown in.
23  */
24
25 #include <sstream>
26 #include <cstdlib>
27 #include <cassert>
28 #include <iomanip>
29 #include <iostream>
30 #include "format.h"
31
32 using namespace std;
33
34 vector<Format const *> Format::_formats;
35
36 /** @param r Ratio multiplied by 100 (e.g. 185)
37  *  @param dcp Size (in pixels) of the images that we should put in a DCP.
38  *  @param id ID (e.g. 185)
39  *  @param n Nick name (e.g. Flat)
40  */
41 Format::Format (int r, Size dcp, string id, string n)
42         : _ratio (r)
43         , _dcp_size (dcp)
44         , _id (id)
45         , _nickname (n)
46 {
47
48 }
49
50 /** @return A name to be presented to the user */
51 string
52 Format::name () const
53 {
54         stringstream s;
55         if (!_nickname.empty ()) {
56                 s << _nickname << " (";
57         }
58
59         s << setprecision(3) << (_ratio / 100.0) << ":1";
60
61         if (!_nickname.empty ()) {
62                 s << ")";
63         }
64
65         return s.str ();
66 }
67
68 /** @return Identifier for this format as metadata for a Film's metadata file */
69 string
70 Format::as_metadata () const
71 {
72         return _id;
73 }
74
75 /** Fill our _formats vector with all available formats */
76 void
77 Format::setup_formats ()
78 {
79         _formats.push_back (new Format (119, Size (1285, 1080), "119", "1.19"));
80         _formats.push_back (new Format (133, Size (1436, 1080), "133", "1.33"));
81         _formats.push_back (new Format (138, Size (1485, 1080), "138", "1.375"));
82         _formats.push_back (new Format (133, Size (1998, 1080), "133-in-flat", "4:3 within Flat"));
83         _formats.push_back (new Format (137, Size (1480, 1080), "137", "Academy"));
84         _formats.push_back (new Format (166, Size (1793, 1080), "166", "1.66"));
85         _formats.push_back (new Format (166, Size (1998, 1080), "166-in-flat", "1.66 within Flat"));
86         _formats.push_back (new Format (178, Size (1998, 1080), "178-in-flat", "16:9 within Flat"));
87         _formats.push_back (new Format (185, Size (1998, 1080), "185", "Flat"));
88         _formats.push_back (new Format (239, Size (2048, 858), "239", "Scope"));
89 }
90
91 /** @param r Ratio multiplied by 100.
92  *  @return Matching Format, or 0.
93  */
94 Format const *
95 Format::from_ratio (int r)
96 {
97         vector<Format const *>::iterator i = _formats.begin ();
98         while (i != _formats.end() && (*i)->ratio_as_integer() != r) {
99                 ++i;
100         }
101
102         if (i == _formats.end ()) {
103                 return 0;
104         }
105
106         return *i;
107 }
108
109 /** @param n Nickname.
110  *  @return Matching Format, or 0.
111  */
112 Format const *
113 Format::from_nickname (string n)
114 {
115         vector<Format const *>::iterator i = _formats.begin ();
116         while (i != _formats.end() && (*i)->nickname() != n) {
117                 ++i;
118         }
119
120         if (i == _formats.end ()) {
121                 return 0;
122         }
123
124         return *i;
125 }
126
127 /** @param i Id.
128  *  @return Matching Format, or 0.
129  */
130 Format const *
131 Format::from_id (string i)
132 {
133         vector<Format const *>::iterator j = _formats.begin ();
134         while (j != _formats.end() && (*j)->id() != i) {
135                 ++j;
136         }
137
138         if (j == _formats.end ()) {
139                 return 0;
140         }
141
142         return *j;
143 }
144
145
146 /** @param m Metadata, as returned from as_metadata().
147  *  @return Matching Format, or 0.
148  */
149 Format const *
150 Format::from_metadata (string m)
151 {
152         return from_id (m);
153 }
154
155 /** @param f A Format.
156  *  @return Index of f within our static list, or -1.
157  */
158 int
159 Format::as_index (Format const * f)
160 {
161         vector<Format*>::size_type i = 0;
162         while (i < _formats.size() && _formats[i] != f) {
163                 ++i;
164         }
165
166         if (i == _formats.size ()) {
167                 return -1;
168         }
169
170         return i;
171 }
172
173 /** @param i An index returned from as_index().
174  *  @return Corresponding Format.
175  */
176 Format const *
177 Format::from_index (int i)
178 {
179         assert (i >= 0 && i < int(_formats.size ()));
180         return _formats[i];
181 }
182
183 /** @return All available formats */
184 vector<Format const *>
185 Format::all ()
186 {
187         return _formats;
188 }
189
190 int
191 Format::dcp_padding () const
192 {
193         int p = rint ((_dcp_size.width - (_dcp_size.height * _ratio / 100.0)) / 2.0);
194
195         /* This comes out -ve for Scope; bodge it */
196         if (p < 0) {
197                 p = 0;
198         }
199         
200         return p;
201 }