libdcp
mono_j2k_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 
40 #include "compose.hpp"
41 #include "dcp_assert.h"
42 #include "equality_options.h"
43 #include "exceptions.h"
44 #include "filesystem.h"
45 #include "mono_j2k_picture_asset.h"
48 #include "mono_j2k_picture_frame.h"
49 #include <asdcp/AS_DCP.h>
50 #include <asdcp/KM_fileio.h>
51 #include <boost/bind/bind.hpp>
52 
53 
54 using std::dynamic_pointer_cast;
55 using std::list;
56 using std::make_shared;
57 using std::pair;
58 using std::shared_ptr;
59 using std::string;
60 using std::vector;
61 #if BOOST_VERSION >= 106100
62 using namespace boost::placeholders;
63 #endif
64 using namespace dcp;
65 
66 
67 MonoJ2KPictureAsset::MonoJ2KPictureAsset (boost::filesystem::path file)
68  : J2KPictureAsset (file)
69 {
70  Kumu::FileReaderFactory factory;
71  ASDCP::JP2K::MXFReader reader(factory);
72  auto r = reader.OpenRead(dcp::filesystem::fix_long_path(file).string().c_str());
73  if (ASDCP_FAILURE(r)) {
74  boost::throw_exception (MXFFileError("could not open MXF file for reading", file.string(), r));
75  }
76 
77  ASDCP::JP2K::PictureDescriptor desc;
78  if (ASDCP_FAILURE (reader.FillPictureDescriptor(desc))) {
79  boost::throw_exception (ReadError("could not read video MXF information"));
80  }
81 
82  read_picture_descriptor (desc);
83 
84  ASDCP::WriterInfo info;
85  if (ASDCP_FAILURE (reader.FillWriterInfo (info))) {
86  boost::throw_exception (ReadError("could not read video MXF information"));
87  }
88 
89  _id = read_writer_info (info);
90 }
91 
92 
93 MonoJ2KPictureAsset::MonoJ2KPictureAsset (Fraction edit_rate, Standard standard)
94  : J2KPictureAsset (edit_rate, standard)
95 {
96 
97 }
98 
99 
100 static void
101 storing_note_handler (list<pair<NoteType, string>>& notes, NoteType t, string s)
102 {
103  notes.push_back (make_pair (t, s));
104 }
105 
106 
107 bool
108 MonoJ2KPictureAsset::equals(shared_ptr<const Asset> other, EqualityOptions const& opt, NoteHandler note) const
109 {
110  if (!dynamic_pointer_cast<const MonoJ2KPictureAsset>(other)) {
111  return false;
112  }
113 
114  Kumu::FileReaderFactory factory;
115  ASDCP::JP2K::MXFReader reader_A(factory);
116  DCP_ASSERT (_file);
117  auto r = reader_A.OpenRead(dcp::filesystem::fix_long_path(*_file).string().c_str());
118  if (ASDCP_FAILURE(r)) {
119  boost::throw_exception (MXFFileError("could not open MXF file for reading", _file->string(), r));
120  }
121 
122  ASDCP::JP2K::MXFReader reader_B(factory);
123  DCP_ASSERT (other->file ());
124  r = reader_B.OpenRead(dcp::filesystem::fix_long_path(*other->file()).string().c_str());
125  if (ASDCP_FAILURE (r)) {
126  boost::throw_exception (MXFFileError ("could not open MXF file for reading", other->file()->string(), r));
127  }
128 
129  ASDCP::JP2K::PictureDescriptor desc_A;
130  if (ASDCP_FAILURE (reader_A.FillPictureDescriptor (desc_A))) {
131  boost::throw_exception (ReadError ("could not read video MXF information"));
132  }
133  ASDCP::JP2K::PictureDescriptor desc_B;
134  if (ASDCP_FAILURE (reader_B.FillPictureDescriptor (desc_B))) {
135  boost::throw_exception (ReadError ("could not read video MXF information"));
136  }
137 
138  if (!descriptor_equals (desc_A, desc_B, note)) {
139  return false;
140  }
141 
142  auto other_picture = dynamic_pointer_cast<const MonoJ2KPictureAsset> (other);
143  DCP_ASSERT (other_picture);
144 
145  bool result = true;
146 
147  auto reader = start_read ();
148  auto other_reader = other_picture->start_read ();
149 
150 #ifdef LIBDCP_OPENMP
151 #pragma omp parallel for
152 #endif
153 
154  for (int i = 0; i < _intrinsic_duration; ++i) {
155  if (i >= other_picture->intrinsic_duration()) {
156  result = false;
157  }
158 
159  if (result || opt.keep_going) {
160 
161  auto frame_A = reader->get_frame (i);
162  auto frame_B = other_reader->get_frame (i);
163 
164  list<pair<NoteType, string>> notes;
165 
166  if (!frame_buffer_equals (
167  i, opt, bind (&storing_note_handler, boost::ref(notes), _1, _2),
168  frame_A->data(), frame_A->size(),
169  frame_B->data(), frame_B->size()
170  )) {
171  result = false;
172  }
173 
174 #ifdef LIBDCP_OPENMP
175 #pragma omp critical
176 #endif
177  {
178  note (NoteType::PROGRESS, String::compose("Compared video frame %1 of %2", i, _intrinsic_duration));
179  for (auto const& i: notes) {
180  note (i.first, i.second);
181  }
182  }
183  }
184  }
185 
186  return result;
187 }
188 
189 
190 shared_ptr<J2KPictureAssetWriter>
191 MonoJ2KPictureAsset::start_write(boost::filesystem::path file, Behaviour behaviour)
192 {
193  /* Can't use make_shared here as the MonoJ2KPictureAssetWriter constructor is private */
194  return shared_ptr<MonoJ2KPictureAssetWriter>(new MonoJ2KPictureAssetWriter(this, file, behaviour == Behaviour::OVERWRITE_EXISTING));
195 }
196 
197 shared_ptr<MonoJ2KPictureAssetReader>
198 MonoJ2KPictureAsset::start_read () const
199 {
200  /* Can't use make_shared here as the MonoJ2KPictureAssetReader constructor is private */
201  return shared_ptr<MonoJ2KPictureAssetReader>(new MonoJ2KPictureAssetReader(this, key(), standard()));
202 
203 }
204 
205 string
206 MonoJ2KPictureAsset::cpl_node_name () const
207 {
208  return "MainPicture";
209 }
boost::optional< boost::filesystem::path > file() const
Definition: asset.h:100
boost::optional< boost::filesystem::path > _file
Definition: asset.h:143
A class to describe what "equality" means for a particular test.
A fraction (i.e. a thing with an integer numerator and an integer denominator).
Definition: types.h:168
An asset made up of JPEG2000 data.
An exception related to an MXF file.
Definition: exceptions.h:82
std::string read_writer_info(ASDCP::WriterInfo const &)
Definition: mxf.cc:124
boost::optional< Key > key() const
Definition: mxf.h:104
A helper class for writing to MonoJ2KPictureAssets.
MonoJ2KPictureAsset(boost::filesystem::path file)
std::shared_ptr< J2KPictureAssetWriter > start_write(boost::filesystem::path file, Behaviour behaviour) override
int64_t _intrinsic_duration
Definition: picture_asset.h:90
Any error that occurs when reading data from a DCP.
Definition: exceptions.h:106
DCP_ASSERT macro.
Class to describe what equality means when calling Asset::equals().
Exceptions thrown by libdcp.
MonoJ2KPictureAsset class.
MonoJ2KPictureAssetReader typedef.
MonoJ2KPictureAssetWriter class.
MonoJ2KPictureFrame class.
Namespace for everything in libdcp.
Definition: array_data.h:50