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