multilayer_metadata.cc (37497B)
1 /* 2 * Copyright (c) 2024, Alliance for Open Media. All rights reserved. 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 12 #include "examples/multilayer_metadata.h" 13 14 #include <assert.h> 15 #include <inttypes.h> 16 #include <limits.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 21 #include <cmath> 22 #include <fstream> 23 #include <iostream> 24 #include <limits> 25 #include <string> 26 #include <vector> 27 28 #include "aom/aom_integer.h" 29 #include "examples/multilayer_metadata.h" 30 31 namespace libaom_examples { 32 33 namespace { 34 35 #define RETURN_IF_FALSE(A) \ 36 do { \ 37 if (!(A)) { \ 38 return false; \ 39 } \ 40 } while (0) 41 42 constexpr int kMaxNumSpatialLayers = 4; 43 44 // Removes comments and trailing spaces from the line. 45 void cleanup_line(std::string &line) { 46 // Remove everything after the first '#'. 47 std::size_t comment_pos = line.find('#'); 48 if (comment_pos != std::string::npos) { 49 line.resize(comment_pos); 50 } 51 // Remove spaces at the end of the line. 52 while (!line.empty() && line.back() == ' ') { 53 line.resize(line.length() - 1); 54 } 55 } 56 57 // Finds the indentation level of the line, and sets 'has_list_prefix' to true 58 // if the line has a '-' indicating a new item in a list. 59 void get_indent(const std::string &line, int *indent, bool *has_list_prefix) { 60 *indent = 0; 61 *has_list_prefix = false; 62 while ( 63 *indent < static_cast<int>(line.length()) && 64 (line[*indent] == ' ' || line[*indent] == '\t' || line[*indent] == '-')) { 65 if (line[*indent] == '-') { 66 *has_list_prefix = true; 67 } 68 ++(*indent); 69 } 70 } 71 72 class ParsedValue { 73 public: 74 enum class Type { kNone, kInteger, kFloatingPoint }; 75 76 void SetIntegerValue(int64_t v) { 77 type_ = Type::kInteger; 78 int_value_ = v; 79 } 80 81 void SetFloatingPointValue(double v) { 82 type_ = Type::kFloatingPoint; 83 double_value_ = v; 84 } 85 86 void Clear() { type_ = Type::kNone; } 87 88 bool ValueAsFloatingPoint(int line_idx, double *v) { 89 if (type_ == Type::kNone) { 90 fprintf( 91 stderr, 92 "No value found where floating point value was expected at line %d\n", 93 line_idx); 94 return false; 95 } 96 *v = (type_ == Type::kFloatingPoint) ? double_value_ 97 : static_cast<double>(int_value_); 98 return true; 99 } 100 101 template <typename T> 102 bool IntegerValueInRange(int64_t min, int64_t max, int line_idx, T *v) { 103 switch (type_) { 104 case Type::kInteger: 105 if (int_value_ < min || int_value_ > max) { 106 fprintf(stderr, 107 "Integer value %" PRId64 " out of range [%" PRId64 108 ", %" PRId64 "] at line %d\n", 109 int_value_, min, max, line_idx); 110 return false; 111 } 112 *v = static_cast<T>(int_value_); 113 return true; 114 case Type::kFloatingPoint: 115 fprintf(stderr, 116 "Floating point value found where integer was expected at line " 117 "%d\n", 118 line_idx); 119 return false; 120 case Type::kNone: 121 default: 122 fprintf(stderr, 123 "No value found where integer was expected at line %d\n", 124 line_idx); 125 return false; 126 } 127 } 128 129 private: 130 Type type_ = Type::kNone; 131 int64_t int_value_ = 0; 132 double double_value_ = 0.0f; 133 }; 134 135 /* 136 * Parses the next line from the file, skipping empty lines. 137 * Returns false if the end of the file was reached, or if the line was indented 138 * less than 'min_indent', meaning that parsing should go back to the previous 139 * function in the stack. 140 * 141 * 'min_indent' is the minimum indentation expected for the next line. 142 * 'is_list' must be true if the line is allowed to contain list items ('-'). 143 * 'indent' MUST be initialized to -1 before the first call, and is then set to 144 * the indentation of the line. 145 * 'has_list_prefix' is set to true if the line starts a new list item with '-'. 146 * 'line_idx' is set to the index of the last line read. 147 * 'field_name' is set to the field name if the line contains a colon, or to an 148 * empty string otherwise. 149 * 'value' is set to the value on the line if present. 150 * In case of syntax error, 'syntax_error' is set to true and the function 151 * returns false. 152 */ 153 bool parse_line(std::ifstream &file, int min_indent, bool is_list, int *indent, 154 bool *has_list_prefix, int *line_idx, std::string *field_name, 155 ParsedValue *value, bool *syntax_error) { 156 *field_name = ""; 157 *syntax_error = false; 158 value->Clear(); 159 std::string line; 160 std::ifstream::pos_type prev_file_position; 161 const int prev_indent = *indent; 162 while (prev_file_position = file.tellg(), std::getline(file, line)) { 163 cleanup_line(line); 164 get_indent(line, indent, has_list_prefix); 165 line = line.substr(*indent); // skip indentation 166 // If the line is indented less than 'min_indent', it belongs to the outer 167 // object, and parsing should go back to the previous function in the stack. 168 if (!line.empty() && 169 (*indent < min_indent || (prev_indent > 0 && *indent < prev_indent))) { 170 // Undo reading the last line. 171 if (!file.seekg(prev_file_position, std::ios::beg)) { 172 fprintf(stderr, "Failed to seek to previous file position\n"); 173 *syntax_error = true; 174 return false; 175 } 176 return false; 177 } 178 179 ++(*line_idx); 180 if (line.empty()) continue; 181 182 if (prev_indent >= 0 && prev_indent != *indent) { 183 fprintf(stderr, "Error: Bad indentation at line %d\n", *line_idx); 184 *syntax_error = true; 185 return false; 186 } 187 if (*has_list_prefix && !is_list) { 188 fprintf(stderr, "Error: Unexpected list item at line %d\n", *line_idx); 189 *syntax_error = true; 190 return false; 191 } 192 193 std::string value_str = line; 194 size_t colon_pos = line.find(':'); 195 if (colon_pos != std::string::npos) { 196 *field_name = line.substr(0, colon_pos); 197 value_str = line.substr(colon_pos + 1); 198 } 199 if (!value_str.empty()) { 200 char *endptr; 201 if (line.find('.') != std::string::npos) { 202 value->SetFloatingPointValue(strtod(value_str.c_str(), &endptr)); 203 if (*endptr != '\0') { 204 fprintf(stderr, 205 "Error: Failed to parse floating point value from '%s' at " 206 "line %d\n", 207 value_str.c_str(), *line_idx); 208 *syntax_error = true; 209 return false; 210 } 211 } else { 212 value->SetIntegerValue(strtol(value_str.c_str(), &endptr, 10)); 213 if (*endptr != '\0') { 214 fprintf(stderr, 215 "Error: Failed to parse integer from '%s' at line %d\n", 216 value_str.c_str(), *line_idx); 217 *syntax_error = true; 218 return false; 219 } 220 } 221 } 222 return true; 223 } 224 return false; // Reached the end of the file. 225 } 226 227 template <typename T> 228 bool parse_integer_list(std::ifstream &file, int min_indent, int *line_idx, 229 std::vector<T> *result) { 230 bool has_list_prefix; 231 int indent = -1; 232 std::string field_name; 233 ParsedValue value; 234 bool syntax_error; 235 while (parse_line(file, min_indent, /*is_list=*/true, &indent, 236 &has_list_prefix, line_idx, &field_name, &value, 237 &syntax_error)) { 238 if (!field_name.empty()) { 239 fprintf( 240 stderr, 241 "Error: Unexpected field name '%s' at line %d, expected a number\n", 242 field_name.c_str(), *line_idx); 243 return false; 244 } else if (!has_list_prefix) { 245 fprintf(stderr, "Error: Missing list prefix '-' at line %d\n", *line_idx); 246 return false; 247 } else { 248 T v; 249 RETURN_IF_FALSE(value.IntegerValueInRange( 250 static_cast<int64_t>(std::numeric_limits<T>::min()), 251 static_cast<int64_t>(std::numeric_limits<T>::max()), *line_idx, &v)); 252 result->push_back(v); 253 } 254 } 255 if (syntax_error) return false; 256 return true; 257 } 258 259 template <typename T> 260 std::pair<T, bool> value_present(const T &v) { 261 return std::make_pair(v, true); 262 } 263 264 bool parse_color_properties(std::ifstream &file, int min_indent, int *line_idx, 265 ColorProperties *color) { 266 bool has_list_prefix; 267 int indent = -1; 268 std::string field_name; 269 ParsedValue value; 270 bool syntax_error; 271 *color = {}; 272 while (parse_line(file, min_indent, /*is_list=*/false, &indent, 273 &has_list_prefix, line_idx, &field_name, &value, 274 &syntax_error)) { 275 if (field_name == "color_range") { 276 RETURN_IF_FALSE(value.IntegerValueInRange(/*min=*/0, /*max=*/1, *line_idx, 277 &color->color_range)); 278 } else if (field_name == "color_primaries") { 279 if (!value.IntegerValueInRange(/*min=*/0, /*max=*/255, *line_idx, 280 &color->color_primaries)) { 281 return false; 282 } 283 } else if (field_name == "transfer_characteristics") { 284 RETURN_IF_FALSE(value.IntegerValueInRange( 285 /*min=*/0, /*max=*/255, *line_idx, &color->transfer_characteristics)); 286 } else if (field_name == "matrix_coefficients") { 287 RETURN_IF_FALSE(value.IntegerValueInRange( 288 /*min=*/0, /*max=*/255, *line_idx, &color->matrix_coefficients)); 289 } else { 290 fprintf(stderr, "Error: Unknown field '%s' at line %d\n", 291 field_name.c_str(), *line_idx); 292 return false; 293 } 294 } 295 if (syntax_error) return false; 296 return true; 297 } 298 299 bool parse_multilayer_layer_alpha(std::ifstream &file, int min_indent, 300 int *line_idx, AlphaInformation *alpha_info) { 301 bool has_list_prefix; 302 int indent = -1; 303 std::string field_name; 304 ParsedValue value; 305 bool syntax_error; 306 *alpha_info = {}; 307 while (parse_line(file, min_indent, /*is_list=*/false, &indent, 308 &has_list_prefix, line_idx, &field_name, &value, 309 &syntax_error)) { 310 if (field_name == "alpha_use_idc") { 311 RETURN_IF_FALSE(value.IntegerValueInRange( 312 /*min=*/0, /*max=*/7, *line_idx, &alpha_info->alpha_use_idc)); 313 } else if (field_name == "alpha_simple_flag") { 314 RETURN_IF_FALSE(value.IntegerValueInRange( 315 /*min=*/0, /*max=*/1, *line_idx, &alpha_info->alpha_simple_flag)); 316 } else if (field_name == "alpha_bit_depth") { 317 RETURN_IF_FALSE(value.IntegerValueInRange( 318 /*min=*/8, /*max=*/15, *line_idx, &alpha_info->alpha_bit_depth)); 319 } else if (field_name == "alpha_clip_idc") { 320 RETURN_IF_FALSE(value.IntegerValueInRange(/*min=*/0, /*max=*/3, *line_idx, 321 &alpha_info->alpha_clip_idc)); 322 } else if (field_name == "alpha_incr_flag") { 323 RETURN_IF_FALSE(value.IntegerValueInRange(/*min=*/0, /*max=*/1, *line_idx, 324 &alpha_info->alpha_incr_flag)); 325 } else if (field_name == "alpha_transparent_value") { 326 // At this point we may not have parsed 'alpha_bit_depth' yet, so the 327 // exact range is checked later. 328 RETURN_IF_FALSE(value.IntegerValueInRange( 329 std::numeric_limits<uint16_t>::min(), 330 std::numeric_limits<uint16_t>::max(), *line_idx, 331 &alpha_info->alpha_transparent_value)); 332 } else if (field_name == "alpha_opaque_value") { 333 // At this point we may not have parsed 'alpha_bit_depth' yet, so the 334 // exact range is checked later. 335 RETURN_IF_FALSE(value.IntegerValueInRange( 336 std::numeric_limits<uint16_t>::min(), 337 std::numeric_limits<uint16_t>::max(), *line_idx, 338 &alpha_info->alpha_opaque_value)); 339 } else if (field_name == "alpha_color_description") { 340 ColorProperties color; 341 RETURN_IF_FALSE(parse_color_properties(file, indent, line_idx, &color)); 342 alpha_info->alpha_color_description = value_present(color); 343 } else { 344 fprintf(stderr, "Error: Unknown field '%s' at line %d\n", 345 field_name.c_str(), *line_idx); 346 return false; 347 } 348 } 349 if (syntax_error) return false; 350 351 // Validation. 352 if (alpha_info->alpha_bit_depth == 0) { 353 fprintf(stderr, 354 "Error: alpha_bit_depth must be specified (in range [8, 15]) for " 355 "alpha info\n"); 356 return false; 357 } 358 const int alpha_max = (1 << (alpha_info->alpha_bit_depth + 1)) - 1; 359 if (alpha_info->alpha_transparent_value > alpha_max) { 360 fprintf(stderr, "Error: alpha_transparent_value %d out of range [0, %d]\n", 361 alpha_info->alpha_transparent_value, alpha_max); 362 return false; 363 } 364 if (alpha_info->alpha_opaque_value > alpha_max) { 365 fprintf(stderr, "Error: alpha_opaque_value %d out of range [0, %d]\n", 366 alpha_info->alpha_opaque_value, alpha_max); 367 return false; 368 } 369 if (alpha_info->alpha_color_description.second && 370 (alpha_info->alpha_use_idc != ALPHA_STRAIGHT)) { 371 fprintf(stderr, 372 "Error: alpha_color_description can only be set if alpha_use_idc " 373 "is %d\n", 374 ALPHA_STRAIGHT); 375 return false; 376 } 377 return true; 378 } 379 380 bool parse_multilayer_layer_depth(std::ifstream &file, int min_indent, 381 int *line_idx, DepthInformation *depth_info) { 382 bool has_list_prefix; 383 int indent = -1; 384 std::string field_name; 385 ParsedValue value; 386 bool syntax_error; 387 *depth_info = {}; 388 while (parse_line(file, min_indent, /*is_list=*/false, &indent, 389 &has_list_prefix, line_idx, &field_name, &value, 390 &syntax_error)) { 391 if (field_name == "z_near") { 392 double tmp; 393 RETURN_IF_FALSE(value.ValueAsFloatingPoint(*line_idx, &tmp)); 394 DepthRepresentationElement el; 395 RETURN_IF_FALSE(double_to_depth_representation_element(tmp, &el)); 396 depth_info->z_near = value_present(el); 397 } else if (field_name == "z_far") { 398 double tmp; 399 RETURN_IF_FALSE(value.ValueAsFloatingPoint(*line_idx, &tmp)); 400 DepthRepresentationElement el; 401 RETURN_IF_FALSE(double_to_depth_representation_element(tmp, &el)); 402 depth_info->z_far = value_present(el); 403 } else if (field_name == "d_min") { 404 double tmp; 405 RETURN_IF_FALSE(value.ValueAsFloatingPoint(*line_idx, &tmp)); 406 DepthRepresentationElement el; 407 RETURN_IF_FALSE(double_to_depth_representation_element(tmp, &el)); 408 depth_info->d_min = value_present(el); 409 } else if (field_name == "d_max") { 410 double tmp; 411 RETURN_IF_FALSE(value.ValueAsFloatingPoint(*line_idx, &tmp)); 412 DepthRepresentationElement el; 413 RETURN_IF_FALSE(double_to_depth_representation_element(tmp, &el)); 414 depth_info->d_max = value_present(el); 415 } else if (field_name == "depth_representation_type") { 416 RETURN_IF_FALSE( 417 value.IntegerValueInRange(/*min=*/0, /*max=*/15, *line_idx, 418 &depth_info->depth_representation_type)); 419 } else if (field_name == "disparity_ref_view_id") { 420 RETURN_IF_FALSE(value.IntegerValueInRange( 421 /*min=*/0, /*max=*/3, *line_idx, &depth_info->disparity_ref_view_id)); 422 } else { 423 fprintf(stderr, "Error: Unknown field '%s' at line %d\n", 424 field_name.c_str(), *line_idx); 425 return false; 426 } 427 } 428 if (syntax_error) return false; 429 430 return true; 431 } 432 433 bool parse_multilayer_layer_local_metadata( 434 std::ifstream &file, int min_indent, int *line_idx, 435 std::vector<FrameLocalMetadata> &frames) { 436 bool has_list_prefix; 437 int indent = -1; 438 std::string field_name; 439 ParsedValue value; 440 bool syntax_error; 441 while (parse_line(file, min_indent, /*is_list=*/true, &indent, 442 &has_list_prefix, line_idx, &field_name, &value, 443 &syntax_error)) { 444 if (has_list_prefix) { 445 frames.push_back({}); 446 } 447 if (frames.empty()) { 448 fprintf(stderr, "Error: Missing list prefix '-' at line %d\n", *line_idx); 449 return false; 450 } 451 452 if (field_name == "frame_idx") { 453 RETURN_IF_FALSE( 454 value.IntegerValueInRange(0, std::numeric_limits<long>::max(), 455 *line_idx, &frames.back().frame_idx)); 456 } else if (field_name == "alpha") { 457 RETURN_IF_FALSE(parse_multilayer_layer_alpha( 458 file, 459 /*min_indent=*/indent + 1, line_idx, &frames.back().alpha)); 460 461 } else if (field_name == "depth") { 462 RETURN_IF_FALSE(parse_multilayer_layer_depth( 463 file, 464 /*min_indent=*/indent + 1, line_idx, &frames.back().depth)); 465 466 } else { 467 fprintf(stderr, "Error: Unknown field %s at line %d\n", 468 field_name.c_str(), *line_idx); 469 return false; 470 } 471 } 472 if (syntax_error) return false; 473 return true; 474 } 475 476 bool validate_layer(const LayerMetadata &layer, bool layer_has_alpha, 477 bool layer_has_depth) { 478 if (layer_has_alpha != (layer.layer_type == MULTILAYER_LAYER_TYPE_ALPHA && 479 layer.layer_metadata_scope >= SCOPE_GLOBAL)) { 480 fprintf(stderr, 481 "Error: alpha info must be set if and only if layer_type is " 482 "%d and layer_metadata_scope is >= %d\n", 483 MULTILAYER_LAYER_TYPE_ALPHA, SCOPE_GLOBAL); 484 return false; 485 } 486 if (layer_has_depth != (layer.layer_type == MULTILAYER_LAYER_TYPE_DEPTH && 487 layer.layer_metadata_scope >= SCOPE_GLOBAL)) { 488 fprintf(stderr, 489 "Error: depth info must be set if and only if layer_type is " 490 "%d and layer_metadata_scope is >= %d\n", 491 MULTILAYER_LAYER_TYPE_DEPTH, SCOPE_GLOBAL); 492 return false; 493 } 494 return true; 495 } 496 497 bool parse_multilayer_layer_metadata(std::ifstream &file, int min_indent, 498 int *line_idx, 499 std::vector<LayerMetadata> &layers) { 500 bool has_list_prefix; 501 int indent = -1; 502 std::string field_name; 503 ParsedValue value; 504 bool syntax_error; 505 bool layer_has_alpha = false; 506 bool layer_has_depth = false; 507 while (parse_line(file, min_indent, /*is_list=*/true, &indent, 508 &has_list_prefix, line_idx, &field_name, &value, 509 &syntax_error)) { 510 if (has_list_prefix) { 511 // Start of a new layer. 512 if (layers.size() >= kMaxNumSpatialLayers) { 513 fprintf(stderr, 514 "Error: Too many layers at line %d, the maximum is %d\n", 515 *line_idx, kMaxNumSpatialLayers); 516 return false; 517 } 518 519 // Validate the previous layer. 520 if (!layers.empty()) { 521 RETURN_IF_FALSE( 522 validate_layer(layers.back(), layer_has_alpha, layer_has_depth)); 523 } 524 if (layers.size() == 1 && layers.back().layer_color_description.second) { 525 fprintf(stderr, 526 "Error: layer_color_description cannot be specified for the " 527 "first layer\n"); 528 return false; 529 } 530 531 layers.push_back({}); 532 layer_has_alpha = false; 533 layer_has_depth = false; 534 } 535 if (layers.empty()) { 536 fprintf(stderr, "Error: Missing list prefix '-' at line %d\n", *line_idx); 537 return false; 538 } 539 540 LayerMetadata *layer = &layers.back(); 541 // Check if string starts with field name. 542 if ((field_name == "layer_type")) { 543 RETURN_IF_FALSE(value.IntegerValueInRange( 544 /*min=*/0, /*max=*/31, *line_idx, &layer->layer_type)); 545 } else if ((field_name == "luma_plane_only_flag")) { 546 RETURN_IF_FALSE(value.IntegerValueInRange(/*min=*/0, /*max=*/1, *line_idx, 547 &layer->luma_plane_only_flag)); 548 } else if ((field_name == "layer_view_type")) { 549 RETURN_IF_FALSE(value.IntegerValueInRange( 550 /*min=*/0, /*max=*/7, *line_idx, &layer->layer_view_type)); 551 } else if ((field_name == "group_id")) { 552 RETURN_IF_FALSE(value.IntegerValueInRange(/*min=*/0, /*max=*/3, *line_idx, 553 &layer->group_id)); 554 } else if ((field_name == "layer_dependency_idc")) { 555 RETURN_IF_FALSE(value.IntegerValueInRange(/*min=*/0, /*max=*/7, *line_idx, 556 &layer->layer_dependency_idc)); 557 } else if ((field_name == "layer_metadata_scope")) { 558 RETURN_IF_FALSE(value.IntegerValueInRange( 559 /*min=*/0, /*max=*/3, *line_idx, &layer->layer_metadata_scope)); 560 } else if ((field_name == "layer_color_description")) { 561 ColorProperties color_properties; 562 RETURN_IF_FALSE( 563 parse_color_properties(file, indent, line_idx, &color_properties)); 564 layer->layer_color_description = value_present(color_properties); 565 } else if ((field_name == "alpha")) { 566 layer_has_alpha = true; 567 RETURN_IF_FALSE(parse_multilayer_layer_alpha(file, 568 /*min_indent=*/indent + 1, 569 line_idx, &layer->alpha)); 570 } else if (field_name == "depth") { 571 layer_has_depth = true; 572 RETURN_IF_FALSE(parse_multilayer_layer_depth(file, 573 /*min_indent=*/indent + 1, 574 line_idx, &layer->depth)); 575 if ((layer->depth.d_min.second || layer->depth.d_max.second) && 576 layer->depth.disparity_ref_view_id == (layers.size() - 1)) { 577 fprintf(stderr, 578 "disparity_ref_view_id must be different from the layer's id " 579 "for layer %d (zero-based index)\n", 580 static_cast<int>(layers.size()) - 1); 581 return false; 582 } 583 } else if (field_name == "local_metadata") { 584 RETURN_IF_FALSE(parse_multilayer_layer_local_metadata( 585 file, /*min_indent=*/indent + 1, line_idx, layer->local_metadata)); 586 } else { 587 fprintf(stderr, "Error: Unknown field %s at line %d\n", 588 field_name.c_str(), *line_idx); 589 return false; 590 } 591 } 592 if (syntax_error) return false; 593 RETURN_IF_FALSE( 594 validate_layer(layers.back(), layer_has_alpha, layer_has_depth)); 595 return true; 596 } 597 598 bool parse_multilayer_metadata(std::ifstream &file, 599 MultilayerMetadata *multilayer) { 600 int line_idx = 0; 601 bool has_list_prefix; 602 int indent = -1; 603 std::string field_name; 604 ParsedValue value; 605 bool syntax_error; 606 *multilayer = {}; 607 while (parse_line(file, /*min_indent=*/0, /*is_list=*/false, &indent, 608 &has_list_prefix, &line_idx, &field_name, &value, 609 &syntax_error)) { 610 // Check if string starts with field name. 611 if ((field_name == "use_case")) { 612 RETURN_IF_FALSE(value.IntegerValueInRange( 613 /*min=*/0, /*max=*/63, line_idx, &multilayer->use_case)); 614 } else if ((field_name == "layers")) { 615 RETURN_IF_FALSE(parse_multilayer_layer_metadata( 616 file, 617 /*min_indent=*/indent + 1, &line_idx, multilayer->layers)); 618 } else { 619 fprintf(stderr, "Error: Unknown field %s at line %d\n", 620 field_name.c_str(), line_idx); 621 return false; 622 } 623 } 624 if (syntax_error) return false; 625 return true; 626 } 627 628 std::string format_depth_representation_element( 629 const std::pair<DepthRepresentationElement, bool> &element) { 630 if (!element.second) { 631 return "absent"; 632 } else { 633 return std::to_string( 634 depth_representation_element_to_double(element.first)) + 635 " (sign " + std::to_string(element.first.sign_flag) + " exponent " + 636 std::to_string(element.first.exponent) + " mantissa " + 637 std::to_string(element.first.mantissa) + " mantissa_len " + 638 std::to_string(element.first.mantissa_len) + ")"; 639 } 640 } 641 642 std::string format_color_properties( 643 const std::pair<ColorProperties, bool> &color_properties) { 644 if (!color_properties.second) { 645 return "absent"; 646 } else { 647 return std::to_string(color_properties.first.color_primaries) + "/" + 648 std::to_string(color_properties.first.transfer_characteristics) + 649 "/" + std::to_string(color_properties.first.matrix_coefficients) + 650 (color_properties.first.color_range ? "F" : "L"); 651 } 652 } 653 654 bool validate_multilayer_metadata(const MultilayerMetadata &multilayer) { 655 if (multilayer.layers.empty()) { 656 fprintf(stderr, "Error: No layers found, there must be at least one\n"); 657 return false; 658 } 659 if (multilayer.layers.size() > 4) { 660 fprintf(stderr, "Error: Too many layers, found %d, max 4\n", 661 static_cast<int>(multilayer.layers.size())); 662 return false; 663 } 664 665 bool same_view_type = true; 666 MultilayerViewType view_type = multilayer.layers[0].layer_view_type; 667 for (const LayerMetadata &layer : multilayer.layers) { 668 if (layer.layer_view_type != view_type) { 669 same_view_type = false; 670 break; 671 } 672 } 673 674 for (int i = 0; i < static_cast<int>(multilayer.layers.size()); ++i) { 675 const LayerMetadata &layer = multilayer.layers[i]; 676 switch (multilayer.use_case) { 677 case MULTILAYER_USE_CASE_GLOBAL_ALPHA: 678 case MULTILAYER_USE_CASE_GLOBAL_DEPTH: 679 case MULTILAYER_USE_CASE_STEREO: 680 case MULTILAYER_USE_CASE_STEREO_GLOBAL_ALPHA: 681 case MULTILAYER_USE_CASE_STEREO_GLOBAL_DEPTH: 682 case MULTILAYER_USE_CASE_444_GLOBAL_ALPHA: 683 case MULTILAYER_USE_CASE_444_GLOBAL_DEPTH: 684 if (layer.layer_metadata_scope != SCOPE_GLOBAL) { 685 fprintf( 686 stderr, 687 "Error: for use_case %d, all layers must have scope %d, found %d " 688 "instead for layer %d (zero-based index)\n", 689 multilayer.use_case, SCOPE_GLOBAL, layer.layer_metadata_scope, i); 690 return false; 691 } 692 break; 693 default: break; 694 } 695 switch (multilayer.use_case) { 696 case MULTILAYER_USE_CASE_GLOBAL_ALPHA: 697 case MULTILAYER_USE_CASE_GLOBAL_DEPTH: 698 case MULTILAYER_USE_CASE_ALPHA: 699 case MULTILAYER_USE_CASE_DEPTH: 700 case MULTILAYER_USE_CASE_444_GLOBAL_ALPHA: 701 case MULTILAYER_USE_CASE_444_GLOBAL_DEPTH: 702 case MULTILAYER_USE_CASE_444: 703 case MULTILAYER_USE_CASE_420_444: 704 if (!same_view_type) { 705 fprintf(stderr, 706 "Error: for use_case %d, all layers must have the same view " 707 "type, found different view_type for layer %d (zero-based " 708 "index)\n", 709 multilayer.use_case, i); 710 return false; 711 } 712 default: break; 713 } 714 if (layer.layer_type != MULTILAYER_LAYER_TYPE_UNSPECIFIED) 715 switch (multilayer.use_case) { 716 case MULTILAYER_USE_CASE_GLOBAL_ALPHA: 717 case MULTILAYER_USE_CASE_ALPHA: 718 case MULTILAYER_USE_CASE_STEREO_GLOBAL_ALPHA: 719 case MULTILAYER_USE_CASE_STEREO_ALPHA: 720 if (layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE && 721 layer.layer_type != MULTILAYER_LAYER_TYPE_ALPHA) { 722 fprintf(stderr, 723 "Error: for use_case %d, all layers must be of type %d or " 724 "%d, found %d for layer %d (zero-based index)\n", 725 multilayer.use_case, MULTILAYER_LAYER_TYPE_TEXTURE, 726 MULTILAYER_LAYER_TYPE_ALPHA, layer.layer_type, i); 727 return false; 728 } 729 break; 730 case MULTILAYER_USE_CASE_GLOBAL_DEPTH: 731 case MULTILAYER_USE_CASE_DEPTH: 732 case MULTILAYER_USE_CASE_STEREO_GLOBAL_DEPTH: 733 case MULTILAYER_USE_CASE_STEREO_DEPTH: 734 if (layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE && 735 layer.layer_type != MULTILAYER_LAYER_TYPE_DEPTH) { 736 fprintf(stderr, 737 "Error: for use_case %d, all layers must be of type %d or " 738 "%d, found %d for layer %d (zero-based index)\n", 739 multilayer.use_case, MULTILAYER_LAYER_TYPE_TEXTURE, 740 MULTILAYER_LAYER_TYPE_DEPTH, layer.layer_type, i); 741 return false; 742 } 743 break; 744 case MULTILAYER_USE_CASE_STEREO: 745 if (layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE) { 746 fprintf(stderr, 747 "Error: for use_case %d, all layers must be of type %d, " 748 "found %d for layer %d (zero-based index)\n", 749 multilayer.use_case, MULTILAYER_LAYER_TYPE_TEXTURE, 750 layer.layer_type, i); 751 return false; 752 } 753 break; 754 case MULTILAYER_USE_CASE_444_GLOBAL_ALPHA: 755 if (layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_1 && 756 layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_2 && 757 layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_3 && 758 layer.layer_type != MULTILAYER_LAYER_TYPE_ALPHA) { 759 fprintf(stderr, 760 "Error: for use_case %d, all layers must be of type %d, " 761 "%d, %d, or %d, found %d for layer %d (zero-based index)\n", 762 multilayer.use_case, MULTILAYER_LAYER_TYPE_TEXTURE_1, 763 MULTILAYER_LAYER_TYPE_TEXTURE_2, 764 MULTILAYER_LAYER_TYPE_TEXTURE_3, 765 MULTILAYER_LAYER_TYPE_ALPHA, layer.layer_type, i); 766 return false; 767 } 768 break; 769 case MULTILAYER_USE_CASE_444_GLOBAL_DEPTH: 770 if (layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_1 && 771 layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_2 && 772 layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_3 && 773 layer.layer_type != MULTILAYER_LAYER_TYPE_DEPTH) { 774 fprintf(stderr, 775 "Error: for use_case %d, all layers must be of type %d, " 776 "%d, %d, or %d, found %d for layer %d (zero-based index)\n", 777 multilayer.use_case, MULTILAYER_LAYER_TYPE_TEXTURE_1, 778 MULTILAYER_LAYER_TYPE_TEXTURE_2, 779 MULTILAYER_LAYER_TYPE_TEXTURE_3, 780 MULTILAYER_LAYER_TYPE_DEPTH, layer.layer_type, i); 781 return false; 782 } 783 break; 784 case MULTILAYER_USE_CASE_444: 785 if (layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_1 && 786 layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_2 && 787 layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_3) { 788 fprintf( 789 stderr, 790 "Error: for use_case %d, all layers must be of type %d, %d, or " 791 "%d, found %d for layer %d (zero-based index)\n", 792 multilayer.use_case, MULTILAYER_LAYER_TYPE_TEXTURE_1, 793 MULTILAYER_LAYER_TYPE_TEXTURE_2, 794 MULTILAYER_LAYER_TYPE_TEXTURE_3, layer.layer_type, i); 795 return false; 796 } 797 break; 798 case MULTILAYER_USE_CASE_420_444: 799 if (layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE && 800 layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_1 && 801 layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_2 && 802 layer.layer_type != MULTILAYER_LAYER_TYPE_TEXTURE_3) { 803 fprintf(stderr, 804 "Error: for use_case %d, all layers must be of type %d, " 805 "%d, %d, or %d, found %d for layer %d (zero-based index)\n", 806 multilayer.use_case, MULTILAYER_LAYER_TYPE_TEXTURE, 807 MULTILAYER_LAYER_TYPE_TEXTURE_1, 808 MULTILAYER_LAYER_TYPE_TEXTURE_2, 809 MULTILAYER_LAYER_TYPE_TEXTURE_3, layer.layer_type, i); 810 return false; 811 } 812 break; 813 default: break; 814 } 815 if (layer.layer_dependency_idc >= (1 << i)) { 816 fprintf(stderr, 817 "Error: layer_dependency_idc of layer %d (zero-based index) must " 818 "be in [0, %d], found %d for layer %d (zero-based index)\n", 819 i, (1 << i) - 1, layer.layer_dependency_idc, i); 820 return false; 821 } 822 if ((layer.layer_type == MULTILAYER_LAYER_TYPE_ALPHA || 823 layer.layer_type == MULTILAYER_LAYER_TYPE_DEPTH) && 824 layer.layer_color_description.second) { 825 fprintf(stderr, 826 "Error: alpha or depth layers cannot have " 827 "layer_color_description for layer %d (zero-based index)\n", 828 i); 829 return false; 830 } 831 } 832 return true; 833 } 834 835 void print_alpha_information(const AlphaInformation &alpha) { 836 printf(" alpha_simple_flag: %d\n", alpha.alpha_simple_flag); 837 if (!alpha.alpha_simple_flag) { 838 printf(" alpha_bit_depth: %d\n", alpha.alpha_bit_depth); 839 printf(" alpha_clip_idc: %d\n", alpha.alpha_clip_idc); 840 printf(" alpha_incr_flag: %d\n", alpha.alpha_incr_flag); 841 printf(" alpha_transparent_value: %hu\n", alpha.alpha_transparent_value); 842 printf(" alpha_opaque_value: %hu\n", alpha.alpha_opaque_value); 843 printf(" alpha_color_description: %s\n", 844 format_color_properties(alpha.alpha_color_description).c_str()); 845 } 846 } 847 848 void print_depth_information(const DepthInformation &depth) { 849 printf(" z_near: %s\n", 850 format_depth_representation_element(depth.z_near).c_str()); 851 printf(" z_far: %s\n", 852 format_depth_representation_element(depth.z_far).c_str()); 853 printf(" d_min: %s\n", 854 format_depth_representation_element(depth.d_min).c_str()); 855 printf(" d_max: %s\n", 856 format_depth_representation_element(depth.d_max).c_str()); 857 printf(" depth_representation_type: %d\n", 858 depth.depth_representation_type); 859 printf(" disparity_ref_view_id: %d\n", depth.disparity_ref_view_id); 860 } 861 862 } // namespace 863 864 double depth_representation_element_to_double( 865 const DepthRepresentationElement &e) { 866 // Let x be a variable that is computed using four variables s, e, m, and n, 867 // as follows: If e is greater than 0 and less than 127, x is set equal to 868 // (−1)^s*2^(e−31) * (1+m÷2^n). 869 // Otherwise (e is equal to 0), x is set equal to (−1)^s*2^−(30+n)*m. 870 if (e.exponent > 0) { 871 return (e.sign_flag ? -1 : 1) * std::pow(2.0, e.exponent - 31) * 872 (1 + static_cast<double>(e.mantissa) / 873 (static_cast<int64_t>(1) << e.mantissa_len)); 874 } else { 875 return (e.sign_flag ? -1 : 1) * e.mantissa * 876 std::pow(2.0, -30 + e.mantissa_len); 877 } 878 } 879 880 bool double_to_depth_representation_element( 881 double v, DepthRepresentationElement *element) { 882 const double orig = v; 883 if (v == 0.0) { 884 *element = { 0, 0, 0, 1 }; 885 return true; 886 } 887 const bool sign = v < 0.0; 888 if (sign) { 889 v = -v; 890 } 891 int exp = 0; 892 if (v >= 1.0) { 893 while (v >= 2.0) { 894 ++exp; 895 v /= 2; 896 } 897 } else { 898 while (v < 1.0) { 899 ++exp; 900 v *= 2.0; 901 } 902 exp = -exp; 903 } 904 if ((exp + 31) <= 0 || (exp + 31) > 126) { 905 fprintf(stderr, 906 "Error: Floating point value %f out of range (too large or too " 907 "small)\n", 908 orig); 909 return false; 910 } 911 assert(v >= 1.0 && v < 2.0); 912 v -= 1.0; 913 uint32_t mantissa = 0; 914 uint8_t mantissa_len = 0; 915 constexpr uint8_t kMaxMantissaLen = 32; 916 do { 917 const int bit = (v >= 0.5); 918 mantissa = (mantissa << 1) + bit; 919 v -= bit * 0.5; 920 ++mantissa_len; 921 v *= 2.0; 922 } while (mantissa_len < kMaxMantissaLen && v > 0.0); 923 *element = { sign, static_cast<uint8_t>(exp + 31), mantissa_len, mantissa }; 924 return true; 925 } 926 927 bool parse_multilayer_file(const char *metadata_path, 928 MultilayerMetadata *multilayer) { 929 std::ifstream file(metadata_path); 930 if (!file.is_open()) { 931 fprintf(stderr, "Error: Failed to open %s\n", metadata_path); 932 return false; 933 } 934 935 if (!parse_multilayer_metadata(file, multilayer) || 936 !validate_multilayer_metadata(*multilayer)) { 937 return false; 938 } 939 return multilayer; 940 } 941 942 void print_multilayer_metadata(const MultilayerMetadata &multilayer) { 943 printf("=== Multilayer metadata ===\n"); 944 printf("use_case: %d\n", multilayer.use_case); 945 for (size_t i = 0; i < multilayer.layers.size(); ++i) { 946 const LayerMetadata &layer = multilayer.layers[i]; 947 printf("layer %zu\n", i); 948 printf(" layer_type: %d\n", layer.layer_type); 949 printf(" luma_plane_only_flag: %d\n", layer.luma_plane_only_flag); 950 printf(" layer_view_type: %d\n", layer.layer_view_type); 951 printf(" group_id: %d\n", layer.group_id); 952 printf(" layer_dependency_idc: %d\n", layer.layer_dependency_idc); 953 printf(" layer_metadata_scope: %d\n", layer.layer_metadata_scope); 954 printf(" layer_color_description: %s\n", 955 format_color_properties(layer.layer_color_description).c_str()); 956 if (layer.layer_type == MULTILAYER_LAYER_TYPE_ALPHA) { 957 if (layer.layer_metadata_scope >= SCOPE_GLOBAL) { 958 printf(" global alpha:\n"); 959 print_alpha_information(layer.alpha); 960 } 961 for (const FrameLocalMetadata &local_metadata : layer.local_metadata) { 962 printf(" local alpha for frame %ld:\n", local_metadata.frame_idx); 963 print_alpha_information(local_metadata.alpha); 964 } 965 } else if (layer.layer_type == MULTILAYER_LAYER_TYPE_DEPTH) { 966 printf(" global depth:\n"); 967 print_depth_information(layer.depth); 968 for (const FrameLocalMetadata &local_metadata : layer.local_metadata) { 969 printf(" local depth for frame %ld:\n", local_metadata.frame_idx); 970 print_depth_information(local_metadata.depth); 971 } 972 } 973 } 974 printf("\n"); 975 } 976 977 } // namespace libaom_examples