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