xref: /aosp_15_r20/external/libaom/tools/obu_parser.cc (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
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