blob: 243ca30bd748422b9bf6ac63ea3cd967bcd58ff0 [file] [log] [blame]
Tom Fineganc0192332017-12-02 09:31:45 -08001/*
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
12#include <cstdio>
13#include <string>
14
15// TODO(tomfinegan): Remove the aom_config.h include as soon as possible. At
Tom Fineganff863952017-12-22 11:41:14 -080016// present it's required because aom_config.h determines if the library writes
17// OBUs.
Tom Fineganc0192332017-12-02 09:31:45 -080018#include "./aom_config.h"
19
Tom Finegan8fe8d512018-03-14 10:38:49 -070020#include "aom/aom_codec.h"
Tom Finegan41150ad2018-01-23 11:42:55 -080021#include "aom/aom_integer.h"
Tom Fineganc0192332017-12-02 09:31:45 -080022#include "aom_ports/mem_ops.h"
Tom Finegan04450b12018-03-19 18:12:28 -070023#include "av1/decoder/obu.h"
Tom Fineganc0192332017-12-02 09:31:45 -080024#include "tools/obu_parser.h"
25
Tom Fineganc0192332017-12-02 09:31:45 -080026namespace aom_tools {
27
28// Basic OBU syntax
29// 4 bytes: length
30// 8 bits: Header
31// 7
32// forbidden bit
33// 6,5,4,3
34// type bits
35// 2,1
36// reserved bits
37// 0
38// extension bit
Tom Finegan2be4e4d2017-12-04 10:22:43 -080039const uint32_t kObuForbiddenBitMask = 0x1;
Tom Fineganc0192332017-12-02 09:31:45 -080040const uint32_t kObuForbiddenBitShift = 7;
Tom Finegan2be4e4d2017-12-04 10:22:43 -080041const uint32_t kObuTypeBitsMask = 0xF;
Tom Fineganc0192332017-12-02 09:31:45 -080042const uint32_t kObuTypeBitsShift = 3;
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -070043const uint32_t kObuExtensionFlagBitMask = 0x1;
44const uint32_t kObuExtensionFlagBitShift = 2;
Tom Finegan04450b12018-03-19 18:12:28 -070045const uint32_t kObuHasPayloadLengthFlagBitMask = 0x1;
46const uint32_t kObuHasPayloadLengthFlagBitShift = 1;
Tom Fineganc0192332017-12-02 09:31:45 -080047
48// When extension bit is set:
49// 8 bits: extension header
50// 7,6,5
51// temporal ID
52// 4,3
53// spatial ID
54// 2,1
55// quality ID
56// 0
57// reserved bit
Tom Finegan2be4e4d2017-12-04 10:22:43 -080058const uint32_t kObuExtTemporalIdBitsMask = 0x7;
Tom Fineganc0192332017-12-02 09:31:45 -080059const uint32_t kObuExtTemporalIdBitsShift = 5;
Tom Finegan2be4e4d2017-12-04 10:22:43 -080060const uint32_t kObuExtSpatialIdBitsMask = 0x3;
Tom Fineganc0192332017-12-02 09:31:45 -080061const uint32_t kObuExtSpatialIdBitsShift = 3;
Tom Fineganc0192332017-12-02 09:31:45 -080062
63bool ValidObuType(int obu_type) {
64 switch (obu_type) {
65 case OBU_SEQUENCE_HEADER:
66 case OBU_TEMPORAL_DELIMITER:
67 case OBU_FRAME_HEADER:
68 case OBU_TILE_GROUP:
Tom Finegan8fe8d512018-03-14 10:38:49 -070069#if CONFIG_OBU_REDUNDANT_FRAME_HEADER
70 case OBU_REDUNDANT_FRAME_HEADER:
71#endif // CONFIG_OBU_REDUNDANT_FRAME_HEADER
Vignesh Venkatasubramanian3871a9e2018-03-13 15:16:53 -070072#if CONFIG_OBU_FRAME
73 case OBU_FRAME:
Tom Finegan8fe8d512018-03-14 10:38:49 -070074#endif // CONFIG_OBU_FRAME
Tom Fineganc0192332017-12-02 09:31:45 -080075 case OBU_METADATA:
76 case OBU_PADDING: return true;
77 }
78 return false;
79}
80
81bool ParseObuHeader(uint8_t obu_header_byte, ObuHeader *obu_header) {
82 const int forbidden_bit =
Tom Finegan2be4e4d2017-12-04 10:22:43 -080083 (obu_header_byte >> kObuForbiddenBitShift) & kObuForbiddenBitMask;
Tom Fineganc0192332017-12-02 09:31:45 -080084 if (forbidden_bit) {
85 fprintf(stderr, "Invalid OBU, forbidden bit set.\n");
86 return false;
87 }
88
Tom Finegan04450b12018-03-19 18:12:28 -070089 obu_header->type = static_cast<OBU_TYPE>(
90 (obu_header_byte >> kObuTypeBitsShift) & kObuTypeBitsMask);
Tom Fineganc0192332017-12-02 09:31:45 -080091 if (!ValidObuType(obu_header->type)) {
92 fprintf(stderr, "Invalid OBU type: %d.\n", obu_header->type);
93 return false;
94 }
95
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -070096 obu_header->has_extension =
97 (obu_header_byte >> kObuExtensionFlagBitShift) & kObuExtensionFlagBitMask;
Tom Finegan04450b12018-03-19 18:12:28 -070098 obu_header->has_length_field =
99 (obu_header_byte >> kObuHasPayloadLengthFlagBitShift) &
100 kObuHasPayloadLengthFlagBitMask;
Tom Fineganc0192332017-12-02 09:31:45 -0800101 return true;
102}
103
Tom Finegan04450b12018-03-19 18:12:28 -0700104bool ParseObuExtensionHeader(uint8_t ext_header_byte, ObuHeader *obu_header) {
105 obu_header->temporal_layer_id =
106 (ext_header_byte >> kObuExtTemporalIdBitsShift) &
107 kObuExtTemporalIdBitsMask;
108 obu_header->enhancement_layer_id =
Tom Finegan2be4e4d2017-12-04 10:22:43 -0800109 (ext_header_byte >> kObuExtSpatialIdBitsShift) & kObuExtSpatialIdBitsMask;
Tom Fineganc0192332017-12-02 09:31:45 -0800110
111 return true;
112}
113
Tom Fineganc0192332017-12-02 09:31:45 -0800114void PrintObuHeader(const ObuHeader *header) {
115 printf(
116 " OBU type: %s\n"
117 " extension: %s\n",
Tom Finegan8fe8d512018-03-14 10:38:49 -0700118 aom_obu_type_to_string(static_cast<OBU_TYPE>(header->type)),
Tom Fineganc0192332017-12-02 09:31:45 -0800119 header->has_extension ? "yes" : "no");
120 if (header->has_extension) {
121 printf(
122 " temporal_id: %d\n"
Tom Finegan04450b12018-03-19 18:12:28 -0700123 " spatial_id: %d\n",
124 header->temporal_layer_id, header->temporal_layer_id);
Tom Fineganc0192332017-12-02 09:31:45 -0800125 }
126}
127
Tom Finegana6f987b2018-02-07 10:02:53 -0800128bool DumpObu(const uint8_t *data, int length, int *obu_overhead_bytes) {
Tom Fineganc0192332017-12-02 09:31:45 -0800129 const int kObuHeaderLengthSizeBytes = 1;
Tom Fineganf2d40f62018-02-01 11:52:49 -0800130 const int kMinimumBytesRequired = 1 + kObuHeaderLengthSizeBytes;
Tom Fineganc0192332017-12-02 09:31:45 -0800131 int consumed = 0;
Tom Finegana6f987b2018-02-07 10:02:53 -0800132 int obu_overhead = 0;
Tom Fineganc0192332017-12-02 09:31:45 -0800133 ObuHeader obu_header;
134 while (consumed < length) {
135 const int remaining = length - consumed;
136 if (remaining < kMinimumBytesRequired) {
137 if (remaining > 0) {
138 fprintf(stderr,
139 "OBU parse error. Did not consume all data, %d bytes "
140 "remain.\n",
141 remaining);
142 }
143 return false;
144 }
145
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -0700146 size_t length_field_size = 0;
147 int current_obu_length = 0;
148 int obu_header_size = 0;
Tom Finegan41150ad2018-01-23 11:42:55 -0800149
Yaowu Xu68dc87e2018-02-28 14:41:50 -0800150 obu_overhead += (int)length_field_size;
Tom Finegana6f987b2018-02-07 10:02:53 -0800151
Tom Fineganc0192332017-12-02 09:31:45 -0800152 if (current_obu_length > remaining) {
153 fprintf(stderr,
154 "OBU parsing failed at offset %d with bad length of %d "
155 "and %d bytes left.\n",
156 consumed, current_obu_length, remaining);
157 return false;
158 }
Yaowu Xu68dc87e2018-02-28 14:41:50 -0800159 consumed += (int)length_field_size;
Tom Fineganc0192332017-12-02 09:31:45 -0800160
Tom Finegan04450b12018-03-19 18:12:28 -0700161 memset(&obu_header, 0, sizeof(obu_header));
Tom Fineganc0192332017-12-02 09:31:45 -0800162 const uint8_t obu_header_byte = *(data + consumed);
163 if (!ParseObuHeader(obu_header_byte, &obu_header)) {
164 fprintf(stderr, "OBU parsing failed at offset %d.\n", consumed);
165 return false;
166 }
167
Tom Finegana6f987b2018-02-07 10:02:53 -0800168 ++obu_overhead;
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -0700169 ++obu_header_size;
Tom Finegana6f987b2018-02-07 10:02:53 -0800170
Tom Fineganc0192332017-12-02 09:31:45 -0800171 if (obu_header.has_extension) {
172 const uint8_t obu_ext_header_byte =
173 *(data + consumed + kObuHeaderLengthSizeBytes);
Tom Finegan04450b12018-03-19 18:12:28 -0700174 if (!ParseObuExtensionHeader(obu_ext_header_byte, &obu_header)) {
Tom Fineganc0192332017-12-02 09:31:45 -0800175 fprintf(stderr, "OBU extension parsing failed at offset %d.\n",
176 consumed);
177 return false;
178 }
Tom Finegana6f987b2018-02-07 10:02:53 -0800179
180 ++obu_overhead;
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -0700181 ++obu_header_size;
Tom Fineganc0192332017-12-02 09:31:45 -0800182 }
183
184 PrintObuHeader(&obu_header);
185
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -0700186 uint64_t obu_size = 0;
187 aom_uleb_decode(data + consumed + obu_header_size, remaining, &obu_size,
188 &length_field_size);
189 current_obu_length = static_cast<int>(obu_size);
Tom Finegan04450b12018-03-19 18:12:28 -0700190 consumed += obu_header_size + length_field_size + current_obu_length;
191 printf(" length: %d\n",
192 static_cast<int>(obu_header_size + length_field_size +
193 current_obu_length));
Tom Fineganc0192332017-12-02 09:31:45 -0800194 }
195
Tom Fineganf4129062018-02-08 08:32:42 -0800196 if (obu_overhead_bytes != nullptr) *obu_overhead_bytes = obu_overhead;
Tom Finegan04450b12018-03-19 18:12:28 -0700197 printf(" TU size: %d\n", consumed);
Tom Finegana6f987b2018-02-07 10:02:53 -0800198
Tom Fineganc0192332017-12-02 09:31:45 -0800199 return true;
200}
201
202} // namespace aom_tools