blob: 7d71386ce4209e0c160c3d4e97d09d9cef3409fc [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 */
Tom Finegan0d91c102018-08-24 21:19:40 -070011#include <string.h>
Tom Fineganc0192332017-12-02 09:31:45 -080012
13#include <cstdio>
14#include <string>
15
Tom Finegan8fe8d512018-03-14 10:38:49 -070016#include "aom/aom_codec.h"
Tom Finegan41150ad2018-01-23 11:42:55 -080017#include "aom/aom_integer.h"
Tom Fineganc0192332017-12-02 09:31:45 -080018#include "aom_ports/mem_ops.h"
Tom Finegan0d91c102018-08-24 21:19:40 -070019#include "av1/common/obu_util.h"
Tom Fineganc0192332017-12-02 09:31:45 -080020#include "tools/obu_parser.h"
21
Tom Fineganc0192332017-12-02 09:31:45 -080022namespace aom_tools {
23
24// Basic OBU syntax
Tom Fineganc0192332017-12-02 09:31:45 -080025// 8 bits: Header
26// 7
27// forbidden bit
28// 6,5,4,3
29// type bits
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -070030// 2
31// extension flag bit
32// 1
33// has size field bit
Tom Fineganc0192332017-12-02 09:31:45 -080034// 0
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -070035// reserved bit
Tom Finegan2be4e4d2017-12-04 10:22:43 -080036const uint32_t kObuForbiddenBitMask = 0x1;
Tom Fineganc0192332017-12-02 09:31:45 -080037const uint32_t kObuForbiddenBitShift = 7;
Tom Finegan2be4e4d2017-12-04 10:22:43 -080038const uint32_t kObuTypeBitsMask = 0xF;
Tom Fineganc0192332017-12-02 09:31:45 -080039const uint32_t kObuTypeBitsShift = 3;
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -070040const uint32_t kObuExtensionFlagBitMask = 0x1;
41const uint32_t kObuExtensionFlagBitShift = 2;
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -070042const uint32_t kObuHasSizeFieldBitMask = 0x1;
43const uint32_t kObuHasSizeFieldBitShift = 1;
Tom Fineganc0192332017-12-02 09:31:45 -080044
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -070045// When extension flag bit is set:
Tom Fineganc0192332017-12-02 09:31:45 -080046// 8 bits: extension header
47// 7,6,5
48// temporal ID
49// 4,3
50// spatial ID
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -070051// 2,1,0
52// reserved bits
Tom Finegan2be4e4d2017-12-04 10:22:43 -080053const uint32_t kObuExtTemporalIdBitsMask = 0x7;
Tom Fineganc0192332017-12-02 09:31:45 -080054const uint32_t kObuExtTemporalIdBitsShift = 5;
Tom Finegan2be4e4d2017-12-04 10:22:43 -080055const uint32_t kObuExtSpatialIdBitsMask = 0x3;
Tom Fineganc0192332017-12-02 09:31:45 -080056const uint32_t kObuExtSpatialIdBitsShift = 3;
Tom Fineganc0192332017-12-02 09:31:45 -080057
58bool ValidObuType(int obu_type) {
59 switch (obu_type) {
60 case OBU_SEQUENCE_HEADER:
61 case OBU_TEMPORAL_DELIMITER:
62 case OBU_FRAME_HEADER:
63 case OBU_TILE_GROUP:
64 case OBU_METADATA:
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -070065 case OBU_FRAME:
66 case OBU_REDUNDANT_FRAME_HEADER:
Yunqing Wang167b09e2018-05-24 16:02:32 -070067 case OBU_TILE_LIST:
Tom Fineganc0192332017-12-02 09:31:45 -080068 case OBU_PADDING: return true;
69 }
70 return false;
71}
72
73bool ParseObuHeader(uint8_t obu_header_byte, ObuHeader *obu_header) {
74 const int forbidden_bit =
Tom Finegan2be4e4d2017-12-04 10:22:43 -080075 (obu_header_byte >> kObuForbiddenBitShift) & kObuForbiddenBitMask;
Tom Fineganc0192332017-12-02 09:31:45 -080076 if (forbidden_bit) {
77 fprintf(stderr, "Invalid OBU, forbidden bit set.\n");
78 return false;
79 }
80
Tom Finegan04450b12018-03-19 18:12:28 -070081 obu_header->type = static_cast<OBU_TYPE>(
82 (obu_header_byte >> kObuTypeBitsShift) & kObuTypeBitsMask);
Tom Fineganc0192332017-12-02 09:31:45 -080083 if (!ValidObuType(obu_header->type)) {
84 fprintf(stderr, "Invalid OBU type: %d.\n", obu_header->type);
85 return false;
86 }
87
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -070088 obu_header->has_extension =
89 (obu_header_byte >> kObuExtensionFlagBitShift) & kObuExtensionFlagBitMask;
Wan-Teh Changb7f1f0c2018-05-30 13:21:09 -070090 obu_header->has_size_field =
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -070091 (obu_header_byte >> kObuHasSizeFieldBitShift) & kObuHasSizeFieldBitMask;
Tom Fineganc0192332017-12-02 09:31:45 -080092 return true;
93}
94
Tom Finegan04450b12018-03-19 18:12:28 -070095bool ParseObuExtensionHeader(uint8_t ext_header_byte, ObuHeader *obu_header) {
96 obu_header->temporal_layer_id =
97 (ext_header_byte >> kObuExtTemporalIdBitsShift) &
98 kObuExtTemporalIdBitsMask;
Soo-Chul Hand2f317c2018-05-08 14:21:24 -040099 obu_header->spatial_layer_id =
Tom Finegan2be4e4d2017-12-04 10:22:43 -0800100 (ext_header_byte >> kObuExtSpatialIdBitsShift) & kObuExtSpatialIdBitsMask;
Tom Fineganc0192332017-12-02 09:31:45 -0800101
102 return true;
103}
104
Tom Fineganc0192332017-12-02 09:31:45 -0800105void PrintObuHeader(const ObuHeader *header) {
106 printf(
107 " OBU type: %s\n"
108 " extension: %s\n",
Tom Finegan8fe8d512018-03-14 10:38:49 -0700109 aom_obu_type_to_string(static_cast<OBU_TYPE>(header->type)),
Tom Fineganc0192332017-12-02 09:31:45 -0800110 header->has_extension ? "yes" : "no");
111 if (header->has_extension) {
112 printf(
113 " temporal_id: %d\n"
Tom Finegan04450b12018-03-19 18:12:28 -0700114 " spatial_id: %d\n",
115 header->temporal_layer_id, header->temporal_layer_id);
Tom Fineganc0192332017-12-02 09:31:45 -0800116 }
117}
118
Tom Finegana6f987b2018-02-07 10:02:53 -0800119bool DumpObu(const uint8_t *data, int length, int *obu_overhead_bytes) {
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -0700120 const int kObuHeaderSizeBytes = 1;
121 const int kMinimumBytesRequired = 1 + kObuHeaderSizeBytes;
Tom Fineganc0192332017-12-02 09:31:45 -0800122 int consumed = 0;
Tom Finegana6f987b2018-02-07 10:02:53 -0800123 int obu_overhead = 0;
Tom Fineganc0192332017-12-02 09:31:45 -0800124 ObuHeader obu_header;
125 while (consumed < length) {
126 const int remaining = length - consumed;
127 if (remaining < kMinimumBytesRequired) {
Tom Fineganc0192332017-12-02 09:31:45 -0800128 fprintf(stderr,
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -0700129 "OBU parse error. Did not consume all data, %d bytes remain.\n",
130 remaining);
Tom Fineganc0192332017-12-02 09:31:45 -0800131 return false;
132 }
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -0700133
134 int obu_header_size = 0;
Tom Fineganc0192332017-12-02 09:31:45 -0800135
Tom Finegan04450b12018-03-19 18:12:28 -0700136 memset(&obu_header, 0, sizeof(obu_header));
Tom Fineganc0192332017-12-02 09:31:45 -0800137 const uint8_t obu_header_byte = *(data + consumed);
138 if (!ParseObuHeader(obu_header_byte, &obu_header)) {
139 fprintf(stderr, "OBU parsing failed at offset %d.\n", consumed);
140 return false;
141 }
142
Tom Finegana6f987b2018-02-07 10:02:53 -0800143 ++obu_overhead;
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -0700144 ++obu_header_size;
Tom Finegana6f987b2018-02-07 10:02:53 -0800145
Tom Fineganc0192332017-12-02 09:31:45 -0800146 if (obu_header.has_extension) {
147 const uint8_t obu_ext_header_byte =
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -0700148 *(data + consumed + kObuHeaderSizeBytes);
Tom Finegan04450b12018-03-19 18:12:28 -0700149 if (!ParseObuExtensionHeader(obu_ext_header_byte, &obu_header)) {
Tom Fineganc0192332017-12-02 09:31:45 -0800150 fprintf(stderr, "OBU extension parsing failed at offset %d.\n",
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -0700151 consumed + kObuHeaderSizeBytes);
Tom Fineganc0192332017-12-02 09:31:45 -0800152 return false;
153 }
Tom Finegana6f987b2018-02-07 10:02:53 -0800154
155 ++obu_overhead;
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -0700156 ++obu_header_size;
Tom Fineganc0192332017-12-02 09:31:45 -0800157 }
158
159 PrintObuHeader(&obu_header);
160
Vignesh Venkatasubramanian01ec41d2018-03-13 15:29:23 -0700161 uint64_t obu_size = 0;
Wan-Teh Chang2a5c2282018-05-29 18:28:10 -0700162 size_t length_field_size = 0;
163 if (aom_uleb_decode(data + consumed + obu_header_size,
164 remaining - obu_header_size, &obu_size,
165 &length_field_size) != 0) {
166 fprintf(stderr, "OBU size parsing failed at offset %d.\n",
167 consumed + obu_header_size);
168 return false;
169 }
170 int current_obu_length = static_cast<int>(obu_size);
171 if (obu_header_size + static_cast<int>(length_field_size) +
172 current_obu_length >
173 remaining) {
174 fprintf(stderr, "OBU parsing failed: not enough OBU data.\n");
175 return false;
176 }
177 consumed += obu_header_size + static_cast<int>(length_field_size) +
178 current_obu_length;
Tom Finegan04450b12018-03-19 18:12:28 -0700179 printf(" length: %d\n",
180 static_cast<int>(obu_header_size + length_field_size +
181 current_obu_length));
Tom Fineganc0192332017-12-02 09:31:45 -0800182 }
183
Tom Fineganf4129062018-02-08 08:32:42 -0800184 if (obu_overhead_bytes != nullptr) *obu_overhead_bytes = obu_overhead;
Tom Finegan04450b12018-03-19 18:12:28 -0700185 printf(" TU size: %d\n", consumed);
Tom Finegana6f987b2018-02-07 10:02:53 -0800186
Tom Fineganc0192332017-12-02 09:31:45 -0800187 return true;
188}
189
190} // namespace aom_tools