3f62c3ebfdccbddd487b30751e43d226d9cc3307
[dcpomatic.git] / src / lib / image_content.cc
1 /*
2     Copyright (C) 2013-2015 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 <libcxml/cxml.h>
21 #include "image_content.h"
22 #include "image_examiner.h"
23 #include "compose.hpp"
24 #include "film.h"
25 #include "job.h"
26 #include "frame_rate_change.h"
27 #include "exceptions.h"
28 #include "safe_stringstream.h"
29
30 #include "i18n.h"
31
32 #include "image_filename_sorter.cc"
33
34 using std::string;
35 using std::cout;
36 using boost::shared_ptr;
37
38 ImageContent::ImageContent (shared_ptr<const Film> film, boost::filesystem::path p)
39         : Content (film)
40         , VideoContent (film)
41 {
42         bool have_j2k = false;
43         if (boost::filesystem::is_regular_file (p) && valid_image_file (p)) {
44                 _paths.push_back (p);
45                 if (valid_j2k_file (p)) {
46                         have_j2k = true;
47                 }
48         } else {
49                 for (boost::filesystem::directory_iterator i(p); i != boost::filesystem::directory_iterator(); ++i) {
50                         if (boost::filesystem::is_regular_file (i->path()) && valid_image_file (i->path())) {
51                                 _paths.push_back (i->path ());
52                                 if (valid_j2k_file (i->path ())) {
53                                         have_j2k = true;
54                                 }
55                         }
56                 }
57
58                 if (_paths.empty()) {
59                         throw FileError (_("No valid image files were found in the folder."), p);
60                 }
61                                 
62                 sort (_paths.begin(), _paths.end(), ImageFilenameSorter ());
63         }
64
65         if (have_j2k) {
66                 /* We default to no colour conversion if we have JPEG2000 files */
67                 unset_colour_conversion (false);
68         }
69 }
70
71
72 ImageContent::ImageContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version)
73         : Content (film, node)
74         , VideoContent (film, node, version)
75 {
76         
77 }
78
79 string
80 ImageContent::summary () const
81 {
82         string s = path_summary () + " ";
83         /* Get the string() here so that the name does not have quotes around it */
84         if (still ()) {
85                 s += _("[still]");
86         } else {
87                 s += _("[moving images]");
88         }
89
90         return s;
91 }
92
93 string
94 ImageContent::technical_summary () const
95 {
96         string s = Content::technical_summary() + " - "
97                 + VideoContent::technical_summary() + " - ";
98
99         if (still ()) {
100                 s += _("still");
101         } else {
102                 s += _("moving");
103         }
104
105         return s;
106 }
107
108 void
109 ImageContent::as_xml (xmlpp::Node* node) const
110 {
111         node->add_child("Type")->add_child_text ("Image");
112         Content::as_xml (node);
113         VideoContent::as_xml (node);
114 }
115
116 void
117 ImageContent::examine (shared_ptr<Job> job)
118 {
119         Content::examine (job);
120
121         shared_ptr<const Film> film = _film.lock ();
122         DCPOMATIC_ASSERT (film);
123         
124         shared_ptr<ImageExaminer> examiner (new ImageExaminer (film, shared_from_this(), job));
125         take_from_video_examiner (examiner);
126 }
127
128 void
129 ImageContent::set_video_length (Frame len)
130 {
131         {
132                 boost::mutex::scoped_lock lm (_mutex);
133                 _video_length = len;
134         }
135
136         signal_changed (ContentProperty::LENGTH);
137 }
138
139 DCPTime
140 ImageContent::full_length () const
141 {
142         shared_ptr<const Film> film = _film.lock ();
143         DCPOMATIC_ASSERT (film);
144         FrameRateChange const frc (video_frame_rate(), film->video_frame_rate());
145         return DCPTime::from_frames (rint (video_length_after_3d_combine() * frc.factor ()), film->video_frame_rate ());
146 }
147
148 string
149 ImageContent::identifier () const
150 {
151         SafeStringStream s;
152         s << VideoContent::identifier ();
153         s << "_" << video_length();
154         return s.str ();
155 }
156
157 bool
158 ImageContent::still () const
159 {
160         return number_of_paths() == 1;
161 }
162
163 void
164 ImageContent::set_video_frame_rate (float r)
165 {
166         {
167                 boost::mutex::scoped_lock lm (_mutex);
168                 if (_video_frame_rate == r) {
169                         return;
170                 }
171                 
172                 _video_frame_rate = r;
173         }
174         
175         signal_changed (VideoContentProperty::VIDEO_FRAME_RATE);
176 }
177
178 void
179 ImageContent::set_default_colour_conversion ()
180 {
181         bool const s = still ();
182
183         boost::mutex::scoped_lock lm (_mutex);
184
185         if (s) {
186                 _colour_conversion = PresetColourConversion::from_id ("srgb").conversion;
187         } else {
188                 _colour_conversion = PresetColourConversion::from_id ("rec709").conversion;
189         }
190 }