Hand-apply d849d411cff28ef5453085791d0b4d7cd73bd070 from master; replace all assert...
[dcpomatic.git] / src / lib / video_content_scale.cc
1 /*
2     Copyright (C) 2013-2014 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 #include "video_content_scale.h"
21 #include "video_content.h"
22 #include "ratio.h"
23 #include "safe_stringstream.h"
24 #include "util.h"
25 #include <libcxml/cxml.h>
26 #include <libxml++/libxml++.h>
27 #include <boost/optional.hpp>
28
29 #include "i18n.h"
30
31 using std::vector;
32 using std::string;
33 using boost::shared_ptr;
34 using boost::optional;
35
36 vector<VideoContentScale> VideoContentScale::_scales;
37
38 VideoContentScale::VideoContentScale (Ratio const * r)
39         : _ratio (r)
40         , _scale (true)
41 {
42
43 }
44
45 VideoContentScale::VideoContentScale ()
46         : _ratio (0)
47         , _scale (false)
48 {
49
50 }
51
52 VideoContentScale::VideoContentScale (bool scale)
53         : _ratio (0)
54         , _scale (scale)
55 {
56
57 }
58
59 VideoContentScale::VideoContentScale (shared_ptr<cxml::Node> node)
60         : _ratio (0)
61         , _scale (true)
62 {
63         optional<string> r = node->optional_string_child ("Ratio");
64         if (r) {
65                 _ratio = Ratio::from_id (r.get ());
66         } else {
67                 _scale = node->bool_child ("Scale");
68         }
69 }
70
71 void
72 VideoContentScale::as_xml (xmlpp::Node* node) const
73 {
74         if (_ratio) {
75                 node->add_child("Ratio")->add_child_text (_ratio->id ());
76         } else {
77                 node->add_child("Scale")->add_child_text (_scale ? "1" : "0");
78         }
79 }
80
81 string
82 VideoContentScale::id () const
83 {
84         SafeStringStream s;
85         
86         if (_ratio) {
87                 s << _ratio->id ();
88         } else {
89                 s << (_scale ? "S1" : "S0");
90         }
91         
92         return s.str ();
93 }
94
95 string
96 VideoContentScale::name () const
97 {
98         if (_ratio) {
99                 return _ratio->nickname ();
100         }
101
102         if (_scale) {
103                 return _("No stretch");
104         }
105
106         return _("No scale");
107 }
108
109 VideoContentScale
110 VideoContentScale::from_id (string id)
111 {
112         Ratio const * r = Ratio::from_id (id);
113         if (r) {
114                 return VideoContentScale (r);
115         }
116
117         if (id == "S0") {
118                 return VideoContentScale (false);
119         }
120
121         return VideoContentScale (true);
122 }
123                 
124 /** @param display_container Size of the container that we are displaying this content in.
125  *  @param film_container The size of the film's image.
126  */
127 dcp::Size
128 VideoContentScale::size (shared_ptr<const VideoContent> c, dcp::Size display_container, dcp::Size film_container, int round) const
129 {
130         if (_ratio) {
131                 return fit_ratio_within (_ratio->ratio (), display_container, round);
132         }
133
134         dcp::Size const ac = c->video_size_after_crop ();
135
136         /* Force scale if the film_container is smaller than the content's image */
137         if (_scale || film_container.width < ac.width || film_container.height < ac.height) {
138                 return fit_ratio_within (ac.ratio (), display_container, round);
139         }
140
141         /* Scale the image so that it will be in the right place in film_container, even if display_container is a
142            different size.
143         */
144         return dcp::Size (
145                 c->video_size().width  * float(display_container.width)  / film_container.width,
146                 c->video_size().height * float(display_container.height) / film_container.height
147                 );
148 }
149
150 void
151 VideoContentScale::setup_scales ()
152 {
153         vector<Ratio const *> ratios = Ratio::all ();
154         for (vector<Ratio const *>::const_iterator i = ratios.begin(); i != ratios.end(); ++i) {
155                 _scales.push_back (VideoContentScale (*i));
156         }
157
158         _scales.push_back (VideoContentScale (true));
159         _scales.push_back (VideoContentScale (false));
160 }
161
162 bool
163 operator== (VideoContentScale const & a, VideoContentScale const & b)
164 {
165         return (a.ratio() == b.ratio() && a.scale() == b.scale());
166 }
167
168 bool
169 operator!= (VideoContentScale const & a, VideoContentScale const & b)
170 {
171         return (a.ratio() != b.ratio() || a.scale() != b.scale());
172 }