Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2017, 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 | */ |
Tom Finegan | 0d91c10 | 2018-08-24 21:19:40 -0700 | [diff] [blame] | 11 | #include <string.h> |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 12 | |
| 13 | #include <cstdio> |
| 14 | #include <string> |
| 15 | |
Tom Finegan | 8fe8d51 | 2018-03-14 10:38:49 -0700 | [diff] [blame] | 16 | #include "aom/aom_codec.h" |
Tom Finegan | 41150ad | 2018-01-23 11:42:55 -0800 | [diff] [blame] | 17 | #include "aom/aom_integer.h" |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 18 | #include "aom_ports/mem_ops.h" |
Tom Finegan | 0d91c10 | 2018-08-24 21:19:40 -0700 | [diff] [blame] | 19 | #include "av1/common/obu_util.h" |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 20 | #include "tools/obu_parser.h" |
| 21 | |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 22 | namespace aom_tools { |
| 23 | |
| 24 | // Basic OBU syntax |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 25 | // 8 bits: Header |
| 26 | // 7 |
| 27 | // forbidden bit |
| 28 | // 6,5,4,3 |
| 29 | // type bits |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 30 | // 2 |
| 31 | // extension flag bit |
| 32 | // 1 |
| 33 | // has size field bit |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 34 | // 0 |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 35 | // reserved bit |
Tom Finegan | 2be4e4d | 2017-12-04 10:22:43 -0800 | [diff] [blame] | 36 | const uint32_t kObuForbiddenBitMask = 0x1; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 37 | const uint32_t kObuForbiddenBitShift = 7; |
Tom Finegan | 2be4e4d | 2017-12-04 10:22:43 -0800 | [diff] [blame] | 38 | const uint32_t kObuTypeBitsMask = 0xF; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 39 | const uint32_t kObuTypeBitsShift = 3; |
Vignesh Venkatasubramanian | 01ec41d | 2018-03-13 15:29:23 -0700 | [diff] [blame] | 40 | const uint32_t kObuExtensionFlagBitMask = 0x1; |
| 41 | const uint32_t kObuExtensionFlagBitShift = 2; |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 42 | const uint32_t kObuHasSizeFieldBitMask = 0x1; |
| 43 | const uint32_t kObuHasSizeFieldBitShift = 1; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 44 | |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 45 | // When extension flag bit is set: |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 46 | // 8 bits: extension header |
| 47 | // 7,6,5 |
| 48 | // temporal ID |
| 49 | // 4,3 |
| 50 | // spatial ID |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 51 | // 2,1,0 |
| 52 | // reserved bits |
Tom Finegan | 2be4e4d | 2017-12-04 10:22:43 -0800 | [diff] [blame] | 53 | const uint32_t kObuExtTemporalIdBitsMask = 0x7; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 54 | const uint32_t kObuExtTemporalIdBitsShift = 5; |
Tom Finegan | 2be4e4d | 2017-12-04 10:22:43 -0800 | [diff] [blame] | 55 | const uint32_t kObuExtSpatialIdBitsMask = 0x3; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 56 | const uint32_t kObuExtSpatialIdBitsShift = 3; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 57 | |
| 58 | bool ValidObuType(int obu_type) { |
| 59 | switch (obu_type) { |
| 60 | case OBU_SEQUENCE_HEADER: |
| 61 | case OBU_TEMPORAL_DELIMITER: |
| 62 | case OBU_FRAME_HEADER: |
| 63 | case OBU_TILE_GROUP: |
| 64 | case OBU_METADATA: |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 65 | case OBU_FRAME: |
| 66 | case OBU_REDUNDANT_FRAME_HEADER: |
Yunqing Wang | 167b09e | 2018-05-24 16:02:32 -0700 | [diff] [blame] | 67 | case OBU_TILE_LIST: |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 68 | case OBU_PADDING: return true; |
| 69 | } |
| 70 | return false; |
| 71 | } |
| 72 | |
| 73 | bool ParseObuHeader(uint8_t obu_header_byte, ObuHeader *obu_header) { |
| 74 | const int forbidden_bit = |
Tom Finegan | 2be4e4d | 2017-12-04 10:22:43 -0800 | [diff] [blame] | 75 | (obu_header_byte >> kObuForbiddenBitShift) & kObuForbiddenBitMask; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 76 | if (forbidden_bit) { |
| 77 | fprintf(stderr, "Invalid OBU, forbidden bit set.\n"); |
| 78 | return false; |
| 79 | } |
| 80 | |
Tom Finegan | 04450b1 | 2018-03-19 18:12:28 -0700 | [diff] [blame] | 81 | obu_header->type = static_cast<OBU_TYPE>( |
| 82 | (obu_header_byte >> kObuTypeBitsShift) & kObuTypeBitsMask); |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 83 | if (!ValidObuType(obu_header->type)) { |
| 84 | fprintf(stderr, "Invalid OBU type: %d.\n", obu_header->type); |
| 85 | return false; |
| 86 | } |
| 87 | |
Vignesh Venkatasubramanian | 01ec41d | 2018-03-13 15:29:23 -0700 | [diff] [blame] | 88 | obu_header->has_extension = |
| 89 | (obu_header_byte >> kObuExtensionFlagBitShift) & kObuExtensionFlagBitMask; |
Wan-Teh Chang | b7f1f0c | 2018-05-30 13:21:09 -0700 | [diff] [blame] | 90 | obu_header->has_size_field = |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 91 | (obu_header_byte >> kObuHasSizeFieldBitShift) & kObuHasSizeFieldBitMask; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 92 | return true; |
| 93 | } |
| 94 | |
Tom Finegan | 04450b1 | 2018-03-19 18:12:28 -0700 | [diff] [blame] | 95 | bool ParseObuExtensionHeader(uint8_t ext_header_byte, ObuHeader *obu_header) { |
| 96 | obu_header->temporal_layer_id = |
| 97 | (ext_header_byte >> kObuExtTemporalIdBitsShift) & |
| 98 | kObuExtTemporalIdBitsMask; |
Soo-Chul Han | d2f317c | 2018-05-08 14:21:24 -0400 | [diff] [blame] | 99 | obu_header->spatial_layer_id = |
Tom Finegan | 2be4e4d | 2017-12-04 10:22:43 -0800 | [diff] [blame] | 100 | (ext_header_byte >> kObuExtSpatialIdBitsShift) & kObuExtSpatialIdBitsMask; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 101 | |
| 102 | return true; |
| 103 | } |
| 104 | |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 105 | void PrintObuHeader(const ObuHeader *header) { |
| 106 | printf( |
| 107 | " OBU type: %s\n" |
| 108 | " extension: %s\n", |
Tom Finegan | 8fe8d51 | 2018-03-14 10:38:49 -0700 | [diff] [blame] | 109 | aom_obu_type_to_string(static_cast<OBU_TYPE>(header->type)), |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 110 | header->has_extension ? "yes" : "no"); |
| 111 | if (header->has_extension) { |
| 112 | printf( |
| 113 | " temporal_id: %d\n" |
Tom Finegan | 04450b1 | 2018-03-19 18:12:28 -0700 | [diff] [blame] | 114 | " spatial_id: %d\n", |
| 115 | header->temporal_layer_id, header->temporal_layer_id); |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 116 | } |
| 117 | } |
| 118 | |
Tom Finegan | a6f987b | 2018-02-07 10:02:53 -0800 | [diff] [blame] | 119 | bool DumpObu(const uint8_t *data, int length, int *obu_overhead_bytes) { |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 120 | const int kObuHeaderSizeBytes = 1; |
| 121 | const int kMinimumBytesRequired = 1 + kObuHeaderSizeBytes; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 122 | int consumed = 0; |
Tom Finegan | a6f987b | 2018-02-07 10:02:53 -0800 | [diff] [blame] | 123 | int obu_overhead = 0; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 124 | ObuHeader obu_header; |
| 125 | while (consumed < length) { |
| 126 | const int remaining = length - consumed; |
| 127 | if (remaining < kMinimumBytesRequired) { |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 128 | fprintf(stderr, |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 129 | "OBU parse error. Did not consume all data, %d bytes remain.\n", |
| 130 | remaining); |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 131 | return false; |
| 132 | } |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 133 | |
| 134 | int obu_header_size = 0; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 135 | |
Tom Finegan | 04450b1 | 2018-03-19 18:12:28 -0700 | [diff] [blame] | 136 | memset(&obu_header, 0, sizeof(obu_header)); |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 137 | const uint8_t obu_header_byte = *(data + consumed); |
| 138 | if (!ParseObuHeader(obu_header_byte, &obu_header)) { |
| 139 | fprintf(stderr, "OBU parsing failed at offset %d.\n", consumed); |
| 140 | return false; |
| 141 | } |
| 142 | |
Tom Finegan | a6f987b | 2018-02-07 10:02:53 -0800 | [diff] [blame] | 143 | ++obu_overhead; |
Vignesh Venkatasubramanian | 01ec41d | 2018-03-13 15:29:23 -0700 | [diff] [blame] | 144 | ++obu_header_size; |
Tom Finegan | a6f987b | 2018-02-07 10:02:53 -0800 | [diff] [blame] | 145 | |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 146 | if (obu_header.has_extension) { |
| 147 | const uint8_t obu_ext_header_byte = |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 148 | *(data + consumed + kObuHeaderSizeBytes); |
Tom Finegan | 04450b1 | 2018-03-19 18:12:28 -0700 | [diff] [blame] | 149 | if (!ParseObuExtensionHeader(obu_ext_header_byte, &obu_header)) { |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 150 | fprintf(stderr, "OBU extension parsing failed at offset %d.\n", |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 151 | consumed + kObuHeaderSizeBytes); |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 152 | return false; |
| 153 | } |
Tom Finegan | a6f987b | 2018-02-07 10:02:53 -0800 | [diff] [blame] | 154 | |
| 155 | ++obu_overhead; |
Vignesh Venkatasubramanian | 01ec41d | 2018-03-13 15:29:23 -0700 | [diff] [blame] | 156 | ++obu_header_size; |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | PrintObuHeader(&obu_header); |
| 160 | |
Vignesh Venkatasubramanian | 01ec41d | 2018-03-13 15:29:23 -0700 | [diff] [blame] | 161 | uint64_t obu_size = 0; |
Wan-Teh Chang | 2a5c228 | 2018-05-29 18:28:10 -0700 | [diff] [blame] | 162 | size_t length_field_size = 0; |
| 163 | if (aom_uleb_decode(data + consumed + obu_header_size, |
| 164 | remaining - obu_header_size, &obu_size, |
| 165 | &length_field_size) != 0) { |
| 166 | fprintf(stderr, "OBU size parsing failed at offset %d.\n", |
| 167 | consumed + obu_header_size); |
| 168 | return false; |
| 169 | } |
| 170 | int current_obu_length = static_cast<int>(obu_size); |
| 171 | if (obu_header_size + static_cast<int>(length_field_size) + |
| 172 | current_obu_length > |
| 173 | remaining) { |
| 174 | fprintf(stderr, "OBU parsing failed: not enough OBU data.\n"); |
| 175 | return false; |
| 176 | } |
| 177 | consumed += obu_header_size + static_cast<int>(length_field_size) + |
| 178 | current_obu_length; |
Tom Finegan | 04450b1 | 2018-03-19 18:12:28 -0700 | [diff] [blame] | 179 | printf(" length: %d\n", |
| 180 | static_cast<int>(obu_header_size + length_field_size + |
| 181 | current_obu_length)); |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 182 | } |
| 183 | |
Tom Finegan | f412906 | 2018-02-08 08:32:42 -0800 | [diff] [blame] | 184 | if (obu_overhead_bytes != nullptr) *obu_overhead_bytes = obu_overhead; |
Tom Finegan | 04450b1 | 2018-03-19 18:12:28 -0700 | [diff] [blame] | 185 | printf(" TU size: %d\n", consumed); |
Tom Finegan | a6f987b | 2018-02-07 10:02:53 -0800 | [diff] [blame] | 186 | |
Tom Finegan | c019233 | 2017-12-02 09:31:45 -0800 | [diff] [blame] | 187 | return true; |
| 188 | } |
| 189 | |
| 190 | } // namespace aom_tools |