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