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
ValidObuType(int obu_type)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
ParseObuHeader(uint8_t obu_header_byte,ObuHeader * obu_header)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
ParseObuExtensionHeader(uint8_t ext_header_byte,ObuHeader * obu_header)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
PrintObuHeader(const ObuHeader * header)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
DumpObu(const uint8_t * data,int length,int * obu_overhead_bytes)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
194