40 #include "compose.hpp"
49 using std::shared_ptr;
51 using std::runtime_error;
54 using boost::optional;
68 dcp::verify_j2k(shared_ptr<const Data> j2k,
int start_index,
int frame_index,
int frame_rate, vector<VerificationNote>& notes)
71 unsigned int const max_tile_part_size = std::floor(200e6 / (8 * frame_rate));
74 auto ptr = j2k->data();
75 auto end = ptr + j2k->size();
77 map<string, uint8_t> markers = {
92 auto marker_name_from_id = [&markers](uint8_t b) -> optional<string> {
93 for (
auto const& i: markers) {
101 auto require_marker = [&](
string name) {
102 if (ptr == end || *ptr != 0xff) {
106 if (ptr == end || *ptr != markers[name]) {
119 auto get_16 = [&]() {
120 if (ptr >= (end - 1)) {
123 auto const a = *ptr++;
124 auto const b = *ptr++;
128 auto get_32 = [&]() -> uint32_t {
129 if (ptr >= (end - 3)) {
132 auto const a = *ptr++;
133 auto const b = *ptr++;
134 auto const c = *ptr++;
135 auto const d = *ptr++;
136 return d | (c << 8) | (b << 16) | (a << 24);
139 auto require_8 = [&](uint8_t value,
string note) {
146 auto require_16 = [&](uint16_t value,
string note) {
153 auto require_32 = [&](uint32_t value,
string note) {
160 require_marker (
"SOC");
161 require_marker (
"SIZ");
162 auto L_siz = get_16();
168 auto const image_width = get_32();
169 auto const image_height = get_32();
170 auto const fourk = image_width > 2048;
171 require_32 (0,
"invalid top-left image x coordinate %1");
172 require_32 (0,
"invalid top-left image y coordinate %1");
173 auto const tile_width = get_32();
174 auto const tile_height = get_32();
175 if (tile_width != image_width || tile_height != image_height) {
176 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_TILE_SIZE });
178 require_32 (0,
"invalid tile anchor x coordinate %1");
179 require_32 (0,
"invalid tile anchor y coordinate %1");
180 require_16 (3,
"invalid component count %1");
181 for (
auto i = 0; i < 3; ++i) {
182 require_8 (12 - 1,
"invalid bit depth %1");
183 require_8 (1,
"invalid horizontal subsampling factor %1");
184 require_8 (1,
"invalid vertical subsampling factor %1");
190 auto num_POC_in_main = 0;
192 auto num_POC_after_main = 0;
193 bool main_header_finished =
false;
198 require_8(0xff,
"missing marker start byte");
199 auto marker_id = get_8();
200 auto marker_name = marker_name_from_id (marker_id);
203 snprintf (buffer, 16,
"%2x", marker_id);
205 }
else if (*marker_name ==
"SOT") {
206 require_16(10,
"invalid SOT size %1");
208 auto const tile_part_length = get_32();
209 auto const tile_part_index = get_8();
210 auto tile_parts = get_8();
211 if (!fourk && tile_parts != 3) {
212 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_TILE_PARTS_FOR_2K, raw_convert<string>(tile_parts) });
214 if (fourk && tile_parts != 6) {
215 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_TILE_PARTS_FOR_4K, raw_convert<string>(tile_parts) });
217 if (tile_part_length > max_tile_part_size) {
218 VerificationNote note{VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_JPEG2000_TILE_PART_SIZE};
219 note.set_frame(frame_index);
220 note.set_frame_rate(frame_rate);
221 note.set_component(tile_part_index);
222 note.set_size(tile_part_length);
223 notes.push_back(note);
225 main_header_finished =
true;
226 }
else if (*marker_name ==
"SOD") {
227 while (ptr < (end - 1) && (ptr[0] != 0xff || ptr[1] < 0x90)) {
230 }
else if (*marker_name ==
"SIZ") {
232 }
else if (*marker_name ==
"COD") {
235 require_8(1,
"invalid coding style %1");
236 require_8(4,
"invalid progression order %1");
237 require_16(1,
"invalid quality layers count %1");
238 require_8(1,
"invalid multi-component transform flag %1");
239 require_8(fourk ? 6 : 5,
"invalid number of transform levels %1");
240 auto log_code_block_width = get_8();
241 if (log_code_block_width != 3) {
242 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_CODE_BLOCK_WIDTH, raw_convert<string>(4 * (2 << log_code_block_width)) });
244 auto log_code_block_height = get_8();
245 if (log_code_block_height != 3) {
246 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_CODE_BLOCK_HEIGHT, raw_convert<string>(4 * (2 << log_code_block_height)) });
248 require_8(0,
"invalid mode variations");
249 require_8(0,
"invalid wavelet transform type %1");
250 require_8(0x77,
"invalid precinct size %1");
251 require_8(0x88,
"invalid precinct size %1");
252 require_8(0x88,
"invalid precinct size %1");
253 require_8(0x88,
"invalid precinct size %1");
254 require_8(0x88,
"invalid precinct size %1");
255 require_8(0x88,
"invalid precinct size %1");
257 require_8(0x88,
"invalid precinct size %1");
259 }
else if (*marker_name ==
"QCD") {
261 auto const L_qcd = get_16();
262 auto quantization_style = get_8();
263 int guard_bits = (quantization_style >> 5) & 7;
264 if (fourk && guard_bits != 2) {
265 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_4K, raw_convert<string>(guard_bits) });
267 if (!fourk && guard_bits != 1) {
268 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_GUARD_BITS_FOR_2K, raw_convert<string>(guard_bits) });
271 }
else if (*marker_name ==
"COC") {
273 auto const coc_component_number = get_8();
278 if (coc_component_number > 2) {
279 throw InvalidCodestream(String::compose(
"invalid COC component number %1", coc_component_number));
281 require_8(1,
"invalid coding style %1");
282 require_8(5,
"invalid number of transform levels %1");
283 require_8(3,
"invalid code block width exponent %1");
284 require_8(3,
"invalid code block height exponent %1");
285 require_8(0,
"invalid mode variations");
286 require_8(0x77,
"invalid precinct size %1");
287 require_8(0x88,
"invalid precinct size %1");
288 require_8(0x88,
"invalid precinct size %1");
289 require_8(0x88,
"invalid precinct size %1");
290 require_8(0x88,
"invalid precinct size %1");
291 require_8(0x88,
"invalid precinct size %1");
292 }
else if (*marker_name ==
"TLM") {
293 auto const len = get_16();
296 }
else if (*marker_name ==
"QCC" || *marker_name ==
"COM") {
297 auto const len = get_16();
299 }
else if (*marker_name ==
"POC") {
300 if (main_header_finished) {
301 num_POC_after_main++;
306 auto require_8_poc = [&](uint16_t value,
string note) {
307 if (get_8() != value) {
308 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER, String::compose(note, value) });
312 auto require_16_poc = [&](uint16_t value,
string note) {
313 if (get_16() != value) {
314 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER, String::compose(note, value) });
318 require_16_poc(16,
"invalid length %1");
319 require_8_poc(0,
"invalid RSpoc %1");
320 require_8_poc(0,
"invalid CSpoc %1");
321 require_16_poc(1,
"invalid LYEpoc %1");
322 require_8_poc(6,
"invalid REpoc %1");
323 require_8_poc(3,
"invalid CEpoc %1");
324 require_8_poc(4,
"invalid Ppoc %1");
325 require_8_poc(6,
"invalid RSpoc %1");
326 require_8_poc(0,
"invalid CSpoc %1");
327 require_16_poc(1,
"invalid LYEpoc %1");
328 require_8_poc(7,
"invalid REpoc %1");
329 require_8_poc(3,
"invalid CEpoc %1");
330 require_8_poc(4,
"invalid Ppoc %1");
346 if (num_POC_in_main != 0 && !fourk) {
347 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER_COUNT_FOR_2K, raw_convert<string>(num_POC_in_main) });
349 if (num_POC_in_main != 1 && fourk) {
350 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_JPEG2000_POC_MARKER_COUNT_FOR_4K, raw_convert<string>(num_POC_in_main) });
352 if (num_POC_after_main != 0) {
353 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_JPEG2000_POC_MARKER_LOCATION });
356 notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_JPEG200_TLM_MARKER });
361 VerificationNote note({VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_JPEG2000_CODESTREAM, string(e.what())});
362 note.set_frame(start_index + frame_index);
363 note.set_frame_rate(frame_rate);
364 notes.push_back(note);
void verify_j2k(std::shared_ptr< const Data > data, int start_index, int frame_index, int frame_rate, std::vector< VerificationNote > ¬es)
P raw_convert(Q, int precision=16, bool fixed=false)
Methods for conversion to/from string.
dcp::verify() method and associated code
Verification that JPEG2000 files meet requirements.