Merge.
[dcpomatic.git] / src / lib / subtitle.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 "subtitle.h"
21 #include "subtitle_content.h"
22 #include "piece.h"
23 #include "image.h"
24 #include "scaler.h"
25 #include "film.h"
26
27 using boost::shared_ptr;
28 using boost::dynamic_pointer_cast;
29 using boost::weak_ptr;
30
31 Subtitle::Subtitle (shared_ptr<const Film> film, libdcp::Size video_container_size, weak_ptr<Piece> weak_piece, shared_ptr<Image> image, dcpomatic::Rect<double> rect, Time from, Time to)
32         : _piece (weak_piece)
33         , _in_image (image)
34         , _in_rect (rect)
35         , _in_from (from)
36         , _in_to (to)
37 {
38         update (film, video_container_size);
39 }
40
41 void
42 Subtitle::update (shared_ptr<const Film> film, libdcp::Size video_container_size)
43 {
44         shared_ptr<Piece> piece = _piece.lock ();
45         if (!piece) {
46                 return;
47         }
48
49         if (!_in_image) {
50                 _out_image.reset ();
51                 return;
52         }
53
54         shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
55         assert (sc);
56
57         dcpomatic::Rect<double> in_rect = _in_rect;
58         libdcp::Size scaled_size;
59
60         in_rect.x += sc->subtitle_x_offset ();
61         in_rect.y += sc->subtitle_y_offset ();
62
63         /* We will scale the subtitle up to fit _video_container_size, and also by the additional subtitle_scale */
64         scaled_size.width = in_rect.width * video_container_size.width * sc->subtitle_scale ();
65         scaled_size.height = in_rect.height * video_container_size.height * sc->subtitle_scale ();
66
67         /* Then we need a corrective translation, consisting of two parts:
68          *
69          * 1.  that which is the result of the scaling of the subtitle by _video_container_size; this will be
70          *     rect.x * _video_container_size.width and rect.y * _video_container_size.height.
71          *
72          * 2.  that to shift the origin of the scale by subtitle_scale to the centre of the subtitle; this will be
73          *     (width_before_subtitle_scale * (1 - subtitle_scale) / 2) and
74          *     (height_before_subtitle_scale * (1 - subtitle_scale) / 2).
75          *
76          * Combining these two translations gives these expressions.
77          */
78         
79         _out_position.x = rint (video_container_size.width * (in_rect.x + (in_rect.width * (1 - sc->subtitle_scale ()) / 2)));
80         _out_position.y = rint (video_container_size.height * (in_rect.y + (in_rect.height * (1 - sc->subtitle_scale ()) / 2)));
81         
82         _out_image = _in_image->scale (
83                 scaled_size,
84                 Scaler::from_id ("bicubic"),
85                 _in_image->pixel_format (),
86                 true
87                 );
88
89         /* XXX: hack */
90         Time from = _in_from;
91         Time to = _in_to;
92         shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (piece->content);
93         if (vc) {
94                 from = rint (from * vc->video_frame_rate() / film->video_frame_rate());
95                 to = rint (to * vc->video_frame_rate() / film->video_frame_rate());
96         }
97         
98         _out_from = from + piece->content->position ();
99         _out_to = to + piece->content->position ();
100
101         check_out_to ();
102 }
103
104 bool
105 Subtitle::covers (Time t) const
106 {
107         return _out_from <= t && t <= _out_to;
108 }
109
110 void
111 Subtitle::check_out_to ()
112 {
113         if (_stop && _out_to > _stop.get ()) {
114                 _out_to = _stop.get ();
115         }
116 }