Make FileError say what path the problem was with.
[dcpomatic.git] / src / lib / active_text.cc
1 /*
2     Copyright (C) 2017-2018 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "active_text.h"
22 #include "text_content.h"
23 #include <boost/shared_ptr.hpp>
24 #include <boost/weak_ptr.hpp>
25
26 using std::list;
27 using std::pair;
28 using std::make_pair;
29 using boost::weak_ptr;
30 using boost::shared_ptr;
31 using boost::optional;
32
33 /** Get the open captions that should be burnt into a given period.
34  *  @param period Period of interest.
35  *  @param always_burn_captions Always burn captions even if their content is not set to burn.
36  */
37 list<PlayerText>
38 ActiveText::get_burnt (DCPTimePeriod period, bool always_burn_captions) const
39 {
40         boost::mutex::scoped_lock lm (_mutex);
41
42         list<PlayerText> ps;
43
44         for (Map::const_iterator i = _data.begin(); i != _data.end(); ++i) {
45
46                 shared_ptr<const TextContent> caption = i->first.lock ();
47                 if (!caption) {
48                         continue;
49                 }
50
51                 if (!caption->use() || (!always_burn_captions && !caption->burn())) {
52                         /* Not burning this content */
53                         continue;
54                 }
55
56                 BOOST_FOREACH (Period j, i->second) {
57                         DCPTimePeriod test (j.from, j.to.get_value_or(DCPTime::max()));
58                         optional<DCPTimePeriod> overlap = period.overlap (test);
59                         if (overlap && overlap->duration() > DCPTime(period.duration().get() / 2)) {
60                                 ps.push_back (j.subs);
61                         }
62                 }
63         }
64
65         return ps;
66 }
67
68 /** Remove subtitles that finish before a given time from our list.
69  *  @param time Time to remove before.
70  */
71 void
72 ActiveText::clear_before (DCPTime time)
73 {
74         boost::mutex::scoped_lock lm (_mutex);
75
76         Map updated;
77         for (Map::const_iterator i = _data.begin(); i != _data.end(); ++i) {
78                 list<Period> as;
79                 BOOST_FOREACH (Period j, i->second) {
80                         if (!j.to || j.to.get() >= time) {
81                                 as.push_back (j);
82                         }
83                 }
84                 if (!as.empty ()) {
85                         updated[i->first] = as;
86                 }
87         }
88         _data = updated;
89 }
90
91 /** Add a new subtitle with a from time.
92  *  @param content Content that the subtitle is from.
93  *  @param ps Subtitles.
94  *  @param from From time for these subtitles.
95  */
96 void
97 ActiveText::add_from (weak_ptr<const TextContent> content, PlayerText ps, DCPTime from)
98 {
99         boost::mutex::scoped_lock lm (_mutex);
100
101         if (_data.find(content) == _data.end()) {
102                 _data[content] = list<Period>();
103         }
104         _data[content].push_back (Period (ps, from));
105 }
106
107 /** Add the to time for the last subtitle added from a piece of content.
108  *  @param content Content that the subtitle is from.
109  *  @param to To time for the last subtitle submitted to add_from for this content.
110  *  @return Return the corresponding subtitles and their from time.
111  */
112 pair<PlayerText, DCPTime>
113 ActiveText::add_to (weak_ptr<const TextContent> content, DCPTime to)
114 {
115         boost::mutex::scoped_lock lm (_mutex);
116
117         DCPOMATIC_ASSERT (_data.find(content) != _data.end());
118
119         _data[content].back().to = to;
120
121         BOOST_FOREACH (StringText& i, _data[content].back().subs.string) {
122                 i.set_out (dcp::Time(to.seconds(), 1000));
123         }
124
125         return make_pair (_data[content].back().subs, _data[content].back().from);
126 }
127
128 /** @param content Some content.
129  *  @return true if we have any active subtitles from this content.
130  */
131 bool
132 ActiveText::have (weak_ptr<const TextContent> content) const
133 {
134         boost::mutex::scoped_lock lm (_mutex);
135
136         Map::const_iterator i = _data.find(content);
137         if (i == _data.end()) {
138                 return false;
139         }
140
141         return !i->second.empty();
142 }
143
144 void
145 ActiveText::clear ()
146 {
147         boost::mutex::scoped_lock lm (_mutex);
148         _data.clear ();
149 }