In-line run of subs_in_out so that it gets the environment more easily.
[libdcp.git] / src / 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/picture_asset.cc
36  *  @brief PictureAsset class
37  */
38
39
40 #include "compose.hpp"
41 #include "dcp_assert.h"
42 #include "equality_options.h"
43 #include "exceptions.h"
44 #include "j2k_transcode.h"
45 #include "openjpeg_image.h"
46 #include "picture_asset.h"
47 #include "picture_asset_writer.h"
48 #include "util.h"
49 #include <asdcp/AS_DCP.h>
50 #include <asdcp/KM_fileio.h>
51 #include <libxml++/nodes/element.h>
52 #include <boost/filesystem.hpp>
53 #include <list>
54 #include <stdexcept>
55
56
57 using std::string;
58 using std::list;
59 using std::vector;
60 using std::max;
61 using std::pair;
62 using std::make_pair;
63 using std::shared_ptr;
64 using namespace dcp;
65
66
67 PictureAsset::PictureAsset (boost::filesystem::path file)
68         : Asset (file)
69 {
70
71 }
72
73
74 PictureAsset::PictureAsset (Fraction edit_rate, Standard standard)
75         : MXF (standard)
76         , _edit_rate (edit_rate)
77 {
78
79 }
80
81
82 void
83 PictureAsset::read_picture_descriptor (ASDCP::JP2K::PictureDescriptor const & desc)
84 {
85         _size.width = desc.StoredWidth;
86         _size.height = desc.StoredHeight;
87         _edit_rate = Fraction (desc.EditRate.Numerator, desc.EditRate.Denominator);
88         _intrinsic_duration = desc.ContainerDuration;
89         _frame_rate = Fraction (desc.SampleRate.Numerator, desc.SampleRate.Denominator);
90         _screen_aspect_ratio = Fraction (desc.AspectRatio.Numerator, desc.AspectRatio.Denominator);
91 }
92
93
94 bool
95 PictureAsset::descriptor_equals (
96         ASDCP::JP2K::PictureDescriptor const & a, ASDCP::JP2K::PictureDescriptor const & b, NoteHandler note
97         ) const
98 {
99         if (
100                 a.EditRate != b.EditRate ||
101                 a.SampleRate != b.SampleRate ||
102                 a.StoredWidth != b.StoredWidth ||
103                 a.StoredHeight != b.StoredHeight ||
104                 a.AspectRatio != b.AspectRatio ||
105                 a.Rsize != b.Rsize ||
106                 a.Xsize != b.Xsize ||
107                 a.Ysize != b.Ysize ||
108                 a.XOsize != b.XOsize ||
109                 a.YOsize != b.YOsize ||
110                 a.XTsize != b.XTsize ||
111                 a.YTsize != b.YTsize ||
112                 a.XTOsize != b.XTOsize ||
113                 a.YTOsize != b.YTOsize ||
114                 a.Csize != b.Csize
115 //              a.CodingStyleDefault != b.CodingStyleDefault ||
116 //              a.QuantizationDefault != b.QuantizationDefault
117                 ) {
118
119                 note (NoteType::ERROR, "video MXF picture descriptors differ");
120                 return false;
121         }
122
123         if (a.ContainerDuration != b.ContainerDuration) {
124                 note (NoteType::ERROR, "video container durations differ");
125         }
126
127 //              for (unsigned int j = 0; j < ASDCP::JP2K::MaxComponents; ++j) {
128 //                      if (a.ImageComponents[j] != b.ImageComponents[j]) {
129 //                              notes.pack_start ("video MXF picture descriptors differ");
130 //                      }
131 //              }
132
133         return true;
134 }
135
136
137 bool
138 PictureAsset::frame_buffer_equals (
139         int frame, EqualityOptions const& opt, NoteHandler note,
140         uint8_t const * data_A, unsigned int size_A, uint8_t const * data_B, unsigned int size_B
141         ) const
142 {
143         if (size_A == size_B && memcmp (data_A, data_B, size_A) == 0) {
144                 note (NoteType::NOTE, "J2K identical");
145                 /* Easy result; the J2K data is identical */
146                 return true;
147         }
148
149         /* Decompress the images to bitmaps */
150         auto image_A = decompress_j2k (const_cast<uint8_t*>(data_A), size_A, 0);
151         auto image_B = decompress_j2k (const_cast<uint8_t*>(data_B), size_B, 0);
152
153         /* Compare them */
154
155         vector<int> abs_diffs (image_A->size().width * image_A->size().height * 3);
156         int d = 0;
157         int max_diff = 0;
158
159         for (int c = 0; c < 3; ++c) {
160
161                 if (image_A->size() != image_B->size()) {
162                         note (NoteType::ERROR, String::compose ("image sizes for frame %1 differ", frame));
163                         return false;
164                 }
165
166                 int const pixels = image_A->size().width * image_A->size().height;
167                 for (int j = 0; j < pixels; ++j) {
168                         int const t = abs (image_A->data(c)[j] - image_B->data(c)[j]);
169                         abs_diffs[d++] = t;
170                         max_diff = max (max_diff, t);
171                 }
172         }
173
174         uint64_t total = 0;
175         for (vector<int>::iterator j = abs_diffs.begin(); j != abs_diffs.end(); ++j) {
176                 total += *j;
177         }
178
179         double const mean = double (total) / abs_diffs.size ();
180
181         uint64_t total_squared_deviation = 0;
182         for (auto j: abs_diffs) {
183                 total_squared_deviation += pow (j - mean, 2);
184         }
185
186         auto const std_dev = sqrt (double (total_squared_deviation) / abs_diffs.size());
187
188         note (NoteType::NOTE, String::compose("mean difference %1 deviation %2", mean, std_dev));
189
190         if (mean > opt.max_mean_pixel_error) {
191                 note (
192                         NoteType::ERROR,
193                         String::compose ("mean %1 out of range %2 in frame %3", mean, opt.max_mean_pixel_error, frame)
194                         );
195
196                 return false;
197         }
198
199         if (std_dev > opt.max_std_dev_pixel_error) {
200                 note (
201                         NoteType::ERROR,
202                         String::compose ("standard deviation %1 out of range %2 in frame %3", std_dev, opt.max_std_dev_pixel_error, frame)
203                         );
204
205                 return false;
206         }
207
208         return true;
209 }
210
211
212 string
213 PictureAsset::static_pkl_type (Standard standard)
214 {
215         switch (standard) {
216         case Standard::INTEROP:
217                 return "application/x-smpte-mxf;asdcpKind=Picture";
218         case Standard::SMPTE:
219                 return "application/mxf";
220         default:
221                 DCP_ASSERT (false);
222         }
223 }
224
225
226 string
227 PictureAsset::pkl_type (Standard standard) const
228 {
229         return static_pkl_type (standard);
230 }