2 * Copyright (c) 2017, Alliance for Open Media. All rights reserved
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.
15 // TODO(tomfinegan): Remove the aom_config.h include as soon as possible. At
16 // present it's required because aom_config.h determines if the library writes
18 #include "./aom_config.h"
20 #include "aom/aom_integer.h"
21 #include "aom_ports/mem_ops.h"
22 #include "tools/obu_parser.h"
25 const aom_tools::ObuExtensionHeader kEmptyObuExt
= { 0, 0, 0, false };
26 const aom_tools::ObuHeader kEmptyObu
= { 0, 0, false, kEmptyObuExt
};
42 const uint32_t kObuForbiddenBitMask
= 0x1;
43 const uint32_t kObuForbiddenBitShift
= 7;
44 const uint32_t kObuTypeBitsMask
= 0xF;
45 const uint32_t kObuTypeBitsShift
= 3;
46 const uint32_t kObuReservedBitsMask
= 0x3;
47 const uint32_t kObuReservedBitsShift
= 1;
48 const uint32_t kObuExtensionFlagBitMask
= 0x1;
50 // When extension bit is set:
51 // 8 bits: extension header
60 const uint32_t kObuExtTemporalIdBitsMask
= 0x7;
61 const uint32_t kObuExtTemporalIdBitsShift
= 5;
62 const uint32_t kObuExtSpatialIdBitsMask
= 0x3;
63 const uint32_t kObuExtSpatialIdBitsShift
= 3;
64 const uint32_t kObuExtQualityIdBitsMask
= 0x3;
65 const uint32_t kObuExtQualityIdBitsShift
= 1;
66 const uint32_t kObuExtReservedFlagBit
= 0x1;
68 bool ValidObuType(int obu_type
) {
70 case OBU_SEQUENCE_HEADER
:
71 case OBU_TEMPORAL_DELIMITER
:
72 case OBU_FRAME_HEADER
:
75 case OBU_PADDING
: return true;
80 bool ParseObuHeader(uint8_t obu_header_byte
, ObuHeader
*obu_header
) {
81 const int forbidden_bit
=
82 (obu_header_byte
>> kObuForbiddenBitShift
) & kObuForbiddenBitMask
;
84 fprintf(stderr
, "Invalid OBU, forbidden bit set.\n");
88 obu_header
->type
= (obu_header_byte
>> kObuTypeBitsShift
) & kObuTypeBitsMask
;
89 if (!ValidObuType(obu_header
->type
)) {
90 fprintf(stderr
, "Invalid OBU type: %d.\n", obu_header
->type
);
94 obu_header
->reserved
=
95 (obu_header_byte
>> kObuReservedBitsShift
) & kObuReservedBitsMask
;
96 if (obu_header
->reserved
!= 0) {
97 fprintf(stderr
, "Invalid OBU: reserved bit(s) set.\n");
101 obu_header
->has_extension
= obu_header_byte
& kObuExtensionFlagBitMask
;
105 bool ParseObuExtensionHeader(uint8_t ext_header_byte
,
106 ObuExtensionHeader
*ext_header
) {
107 ext_header
->temporal_id
= (ext_header_byte
>> kObuExtTemporalIdBitsShift
) &
108 kObuExtTemporalIdBitsMask
;
109 ext_header
->spatial_id
=
110 (ext_header_byte
>> kObuExtSpatialIdBitsShift
) & kObuExtSpatialIdBitsMask
;
111 ext_header
->quality_id
=
112 (ext_header_byte
>> kObuExtQualityIdBitsShift
) & kObuExtQualityIdBitsMask
;
113 ext_header
->reserved_flag
= ext_header_byte
& kObuExtReservedFlagBit
;
115 if (ext_header
->reserved_flag
) {
116 fprintf(stderr
, "Invalid OBU Extension: reserved flag set.\n");
123 std::string
ObuTypeToString(int obu_type
) {
125 case OBU_SEQUENCE_HEADER
: return "OBU_SEQUENCE_HEADER";
126 case OBU_TEMPORAL_DELIMITER
: return "OBU_TEMPORAL_DELIMITER";
127 case OBU_FRAME_HEADER
: return "OBU_FRAME_HEADER";
128 case OBU_TILE_GROUP
: return "OBU_TILE_GROUP";
129 case OBU_METADATA
: return "OBU_METADATA";
130 case OBU_PADDING
: return "OBU_PADDING";
135 void PrintObuHeader(const ObuHeader
*header
) {
139 ObuTypeToString(header
->type
).c_str(),
140 header
->has_extension
? "yes" : "no");
141 if (header
->has_extension
) {
146 header
->ext_header
.temporal_id
, header
->ext_header
.spatial_id
,
147 header
->ext_header
.quality_id
);
151 bool DumpObu(const uint8_t *data
, int length
, int *obu_overhead_bytes
) {
152 const int kObuHeaderLengthSizeBytes
= 1;
153 const int kMinimumBytesRequired
= 1 + kObuHeaderLengthSizeBytes
;
155 int obu_overhead
= 0;
156 ObuHeader obu_header
;
157 while (consumed
< length
) {
158 const int remaining
= length
- consumed
;
159 if (remaining
< kMinimumBytesRequired
) {
162 "OBU parse error. Did not consume all data, %d bytes "
169 #if CONFIG_OBU_SIZING
170 uint64_t obu_size
= 0;
171 size_t length_field_size
;
172 aom_uleb_decode(data
+ consumed
, remaining
, &obu_size
, &length_field_size
);
173 const int current_obu_length
= static_cast<int>(obu_size
);
175 const int current_obu_length
= mem_get_le32(data
+ consumed
);
176 const int kObuLengthFieldSizeBytes
= 4;
177 const size_t length_field_size
= kObuLengthFieldSizeBytes
;
178 #endif // CONFIG_OBU_SIZING
180 obu_overhead
+= (int)length_field_size
;
182 if (current_obu_length
> remaining
) {
184 "OBU parsing failed at offset %d with bad length of %d "
185 "and %d bytes left.\n",
186 consumed
, current_obu_length
, remaining
);
189 consumed
+= (int)length_field_size
;
191 obu_header
= kEmptyObu
;
192 const uint8_t obu_header_byte
= *(data
+ consumed
);
193 if (!ParseObuHeader(obu_header_byte
, &obu_header
)) {
194 fprintf(stderr
, "OBU parsing failed at offset %d.\n", consumed
);
200 if (obu_header
.has_extension
) {
201 const uint8_t obu_ext_header_byte
=
202 *(data
+ consumed
+ kObuHeaderLengthSizeBytes
);
203 if (!ParseObuExtensionHeader(obu_ext_header_byte
,
204 &obu_header
.ext_header
)) {
205 fprintf(stderr
, "OBU extension parsing failed at offset %d.\n",
213 PrintObuHeader(&obu_header
);
215 // TODO(tomfinegan): Parse OBU payload. For now just consume it.
216 consumed
+= current_obu_length
;
219 if (obu_overhead_bytes
!= nullptr) *obu_overhead_bytes
= obu_overhead
;
224 } // namespace aom_tools