Bump the PNG subtitle / font buffer a little.
[libdcp.git] / src / mono_picture_asset.cc
1 /*
2     Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
6     libdcp 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     libdcp 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 libdcp.  If not, see <http://www.gnu.org/licenses/>.
18
19     In addition, as a special exception, the copyright holders give
20     permission to link the code of portions of this program with the
21     OpenSSL library under certain conditions as described in each
22     individual source file, and distribute linked combinations
23     including the two.
24
25     You must obey the GNU General Public License in all respects
26     for all of the code used other than OpenSSL.  If you modify
27     file(s) with this exception, you may extend this exception to your
28     version of the file(s), but you are not obligated to do so.  If you
29     do not wish to do so, delete this exception statement from your
30     version.  If you delete this exception statement from all source
31     files in the program, then also delete it here.
32 */
33
34
35 /** @file  src/mono_picture_asset.cc
36  *  @brief MonoPictureAsset class
37  */
38
39
40 #include "compose.hpp"
41 #include "dcp_assert.h"
42 #include "equality_options.h"
43 #include "exceptions.h"
44 #include "mono_picture_asset.h"
45 #include "mono_picture_asset_reader.h"
46 #include "mono_picture_asset_writer.h"
47 #include "mono_picture_frame.h"
48 #include <asdcp/AS_DCP.h>
49 #include <asdcp/KM_fileio.h>
50
51
52 using std::string;
53 using std::vector;
54 using std::list;
55 using std::pair;
56 using std::shared_ptr;
57 using std::dynamic_pointer_cast;
58 using std::make_shared;
59 #if BOOST_VERSION >= 106100
60 using namespace boost::placeholders;
61 #endif
62 using namespace dcp;
63
64
65 MonoPictureAsset::MonoPictureAsset (boost::filesystem::path file)
66         : PictureAsset (file)
67 {
68         ASDCP::JP2K::MXFReader reader;
69         auto r = reader.OpenRead (file.string().c_str());
70         if (ASDCP_FAILURE(r)) {
71                 boost::throw_exception (MXFFileError("could not open MXF file for reading", file.string(), r));
72         }
73
74         ASDCP::JP2K::PictureDescriptor desc;
75         if (ASDCP_FAILURE (reader.FillPictureDescriptor(desc))) {
76                 boost::throw_exception (ReadError("could not read video MXF information"));
77         }
78
79         read_picture_descriptor (desc);
80
81         ASDCP::WriterInfo info;
82         if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
83                 boost::throw_exception (ReadError("could not read video MXF information"));
84         }
85
86         _id = read_writer_info (info);
87 }
88
89
90 MonoPictureAsset::MonoPictureAsset (Fraction edit_rate, Standard standard)
91         : PictureAsset (edit_rate, standard)
92 {
93
94 }
95
96
97 static void
98 storing_note_handler (list<pair<NoteType, string>>& notes, NoteType t, string s)
99 {
100         notes.push_back (make_pair (t, s));
101 }
102
103
104 bool
105 MonoPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const& opt, NoteHandler note) const
106 {
107         if (!dynamic_pointer_cast<const MonoPictureAsset>(other)) {
108                 return false;
109         }
110
111         ASDCP::JP2K::MXFReader reader_A;
112         DCP_ASSERT (_file);
113         auto r = reader_A.OpenRead (_file->string().c_str());
114         if (ASDCP_FAILURE(r)) {
115                 boost::throw_exception (MXFFileError("could not open MXF file for reading", _file->string(), r));
116         }
117
118         ASDCP::JP2K::MXFReader reader_B;
119         DCP_ASSERT (other->file ());
120         r = reader_B.OpenRead (other->file()->string().c_str());
121         if (ASDCP_FAILURE (r)) {
122                 boost::throw_exception (MXFFileError ("could not open MXF file for reading", other->file()->string(), r));
123         }
124
125         ASDCP::JP2K::PictureDescriptor desc_A;
126         if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
127                 boost::throw_exception (ReadError ("could not read video MXF information"));
128         }
129         ASDCP::JP2K::PictureDescriptor desc_B;
130         if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
131                 boost::throw_exception (ReadError ("could not read video MXF information"));
132         }
133
134         if (!descriptor_equals (desc_A, desc_B, note)) {
135                 return false;
136         }
137
138         auto other_picture = dynamic_pointer_cast<const MonoPictureAsset> (other);
139         DCP_ASSERT (other_picture);
140
141         bool result = true;
142
143         auto reader = start_read ();
144         auto other_reader = other_picture->start_read ();
145
146 #ifdef LIBDCP_OPENMP
147 #pragma omp parallel for
148 #endif
149
150         for (int i = 0; i < _intrinsic_duration; ++i) {
151                 if (i >= other_picture->intrinsic_duration()) {
152                         result = false;
153                 }
154
155                 if (result || opt.keep_going) {
156
157                         auto frame_A = reader->get_frame (i);
158                         auto frame_B = other_reader->get_frame (i);
159
160                         list<pair<NoteType, string>> notes;
161
162                         if (!frame_buffer_equals (
163                                     i, opt, bind (&storing_note_handler, boost::ref(notes), _1, _2),
164                                     frame_A->data(), frame_A->size(),
165                                     frame_B->data(), frame_B->size()
166                                     )) {
167                                 result = false;
168                         }
169
170 #ifdef LIBDCP_OPENMP
171 #pragma omp critical
172 #endif
173                         {
174                                 note (NoteType::PROGRESS, String::compose("Compared video frame %1 of %2", i, _intrinsic_duration));
175                                 for (auto const& i: notes) {
176                                         note (i.first, i.second);
177                                 }
178                         }
179                 }
180         }
181
182         return result;
183 }
184
185
186 shared_ptr<PictureAssetWriter>
187 MonoPictureAsset::start_write(boost::filesystem::path file, Behaviour behaviour)
188 {
189         /* Can't use make_shared here as the MonoPictureAssetWriter constructor is private */
190         return shared_ptr<MonoPictureAssetWriter>(new MonoPictureAssetWriter(this, file, behaviour == Behaviour::OVERWRITE_EXISTING));
191 }
192
193 shared_ptr<MonoPictureAssetReader>
194 MonoPictureAsset::start_read () const
195 {
196         /* Can't use make_shared here as the MonoPictureAssetReader constructor is private */
197         return shared_ptr<MonoPictureAssetReader>(new MonoPictureAssetReader(this, key(), standard()));
198
199 }
200
201 string
202 MonoPictureAsset::cpl_node_name () const
203 {
204         return "MainPicture";
205 }