1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker * Copyright (c) 2017, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker *
4*77c1e3ccSAndroid Build Coastguard Worker * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker */
11*77c1e3ccSAndroid Build Coastguard Worker #include <string.h>
12*77c1e3ccSAndroid Build Coastguard Worker
13*77c1e3ccSAndroid Build Coastguard Worker #include <cstdio>
14*77c1e3ccSAndroid Build Coastguard Worker #include <string>
15*77c1e3ccSAndroid Build Coastguard Worker
16*77c1e3ccSAndroid Build Coastguard Worker #include "aom/aom_codec.h"
17*77c1e3ccSAndroid Build Coastguard Worker #include "aom/aom_integer.h"
18*77c1e3ccSAndroid Build Coastguard Worker #include "aom_ports/mem_ops.h"
19*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/obu_util.h"
20*77c1e3ccSAndroid Build Coastguard Worker #include "tools/obu_parser.h"
21*77c1e3ccSAndroid Build Coastguard Worker
22*77c1e3ccSAndroid Build Coastguard Worker namespace aom_tools {
23*77c1e3ccSAndroid Build Coastguard Worker namespace {
24*77c1e3ccSAndroid Build Coastguard Worker
25*77c1e3ccSAndroid Build Coastguard Worker // Basic OBU syntax
26*77c1e3ccSAndroid Build Coastguard Worker // 8 bits: Header
27*77c1e3ccSAndroid Build Coastguard Worker // 7
28*77c1e3ccSAndroid Build Coastguard Worker // forbidden bit
29*77c1e3ccSAndroid Build Coastguard Worker // 6,5,4,3
30*77c1e3ccSAndroid Build Coastguard Worker // type bits
31*77c1e3ccSAndroid Build Coastguard Worker // 2
32*77c1e3ccSAndroid Build Coastguard Worker // extension flag bit
33*77c1e3ccSAndroid Build Coastguard Worker // 1
34*77c1e3ccSAndroid Build Coastguard Worker // has size field bit
35*77c1e3ccSAndroid Build Coastguard Worker // 0
36*77c1e3ccSAndroid Build Coastguard Worker // reserved bit
37*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuForbiddenBitMask = 0x1;
38*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuForbiddenBitShift = 7;
39*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuTypeBitsMask = 0xF;
40*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuTypeBitsShift = 3;
41*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuExtensionFlagBitMask = 0x1;
42*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuExtensionFlagBitShift = 2;
43*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuHasSizeFieldBitMask = 0x1;
44*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuHasSizeFieldBitShift = 1;
45*77c1e3ccSAndroid Build Coastguard Worker
46*77c1e3ccSAndroid Build Coastguard Worker // When extension flag bit is set:
47*77c1e3ccSAndroid Build Coastguard Worker // 8 bits: extension header
48*77c1e3ccSAndroid Build Coastguard Worker // 7,6,5
49*77c1e3ccSAndroid Build Coastguard Worker // temporal ID
50*77c1e3ccSAndroid Build Coastguard Worker // 4,3
51*77c1e3ccSAndroid Build Coastguard Worker // spatial ID
52*77c1e3ccSAndroid Build Coastguard Worker // 2,1,0
53*77c1e3ccSAndroid Build Coastguard Worker // reserved bits
54*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuExtTemporalIdBitsMask = 0x7;
55*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuExtTemporalIdBitsShift = 5;
56*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuExtSpatialIdBitsMask = 0x3;
57*77c1e3ccSAndroid Build Coastguard Worker const uint32_t kObuExtSpatialIdBitsShift = 3;
58*77c1e3ccSAndroid Build Coastguard Worker
ValidObuType(int obu_type)59*77c1e3ccSAndroid Build Coastguard Worker bool ValidObuType(int obu_type) {
60*77c1e3ccSAndroid Build Coastguard Worker switch (obu_type) {
61*77c1e3ccSAndroid Build Coastguard Worker case OBU_SEQUENCE_HEADER:
62*77c1e3ccSAndroid Build Coastguard Worker case OBU_TEMPORAL_DELIMITER:
63*77c1e3ccSAndroid Build Coastguard Worker case OBU_FRAME_HEADER:
64*77c1e3ccSAndroid Build Coastguard Worker case OBU_TILE_GROUP:
65*77c1e3ccSAndroid Build Coastguard Worker case OBU_METADATA:
66*77c1e3ccSAndroid Build Coastguard Worker case OBU_FRAME:
67*77c1e3ccSAndroid Build Coastguard Worker case OBU_REDUNDANT_FRAME_HEADER:
68*77c1e3ccSAndroid Build Coastguard Worker case OBU_TILE_LIST:
69*77c1e3ccSAndroid Build Coastguard Worker case OBU_PADDING: return true;
70*77c1e3ccSAndroid Build Coastguard Worker }
71*77c1e3ccSAndroid Build Coastguard Worker return false;
72*77c1e3ccSAndroid Build Coastguard Worker }
73*77c1e3ccSAndroid Build Coastguard Worker
ParseObuHeader(uint8_t obu_header_byte,ObuHeader * obu_header)74*77c1e3ccSAndroid Build Coastguard Worker bool ParseObuHeader(uint8_t obu_header_byte, ObuHeader *obu_header) {
75*77c1e3ccSAndroid Build Coastguard Worker const int forbidden_bit =
76*77c1e3ccSAndroid Build Coastguard Worker (obu_header_byte >> kObuForbiddenBitShift) & kObuForbiddenBitMask;
77*77c1e3ccSAndroid Build Coastguard Worker if (forbidden_bit) {
78*77c1e3ccSAndroid Build Coastguard Worker fprintf(stderr, "Invalid OBU, forbidden bit set.\n");
79*77c1e3ccSAndroid Build Coastguard Worker return false;
80*77c1e3ccSAndroid Build Coastguard Worker }
81*77c1e3ccSAndroid Build Coastguard Worker
82*77c1e3ccSAndroid Build Coastguard Worker obu_header->type = static_cast<OBU_TYPE>(
83*77c1e3ccSAndroid Build Coastguard Worker (obu_header_byte >> kObuTypeBitsShift) & kObuTypeBitsMask);
84*77c1e3ccSAndroid Build Coastguard Worker if (!ValidObuType(obu_header->type)) {
85*77c1e3ccSAndroid Build Coastguard Worker fprintf(stderr, "Invalid OBU type: %d.\n", obu_header->type);
86*77c1e3ccSAndroid Build Coastguard Worker return false;
87*77c1e3ccSAndroid Build Coastguard Worker }
88*77c1e3ccSAndroid Build Coastguard Worker
89*77c1e3ccSAndroid Build Coastguard Worker obu_header->has_extension =
90*77c1e3ccSAndroid Build Coastguard Worker (obu_header_byte >> kObuExtensionFlagBitShift) & kObuExtensionFlagBitMask;
91*77c1e3ccSAndroid Build Coastguard Worker obu_header->has_size_field =
92*77c1e3ccSAndroid Build Coastguard Worker (obu_header_byte >> kObuHasSizeFieldBitShift) & kObuHasSizeFieldBitMask;
93*77c1e3ccSAndroid Build Coastguard Worker return true;
94*77c1e3ccSAndroid Build Coastguard Worker }
95*77c1e3ccSAndroid Build Coastguard Worker
ParseObuExtensionHeader(uint8_t ext_header_byte,ObuHeader * obu_header)96*77c1e3ccSAndroid Build Coastguard Worker bool ParseObuExtensionHeader(uint8_t ext_header_byte, ObuHeader *obu_header) {
97*77c1e3ccSAndroid Build Coastguard Worker obu_header->temporal_layer_id =
98*77c1e3ccSAndroid Build Coastguard Worker (ext_header_byte >> kObuExtTemporalIdBitsShift) &
99*77c1e3ccSAndroid Build Coastguard Worker kObuExtTemporalIdBitsMask;
100*77c1e3ccSAndroid Build Coastguard Worker obu_header->spatial_layer_id =
101*77c1e3ccSAndroid Build Coastguard Worker (ext_header_byte >> kObuExtSpatialIdBitsShift) & kObuExtSpatialIdBitsMask;
102*77c1e3ccSAndroid Build Coastguard Worker
103*77c1e3ccSAndroid Build Coastguard Worker return true;
104*77c1e3ccSAndroid Build Coastguard Worker }
105*77c1e3ccSAndroid Build Coastguard Worker
PrintObuHeader(const ObuHeader * header)106*77c1e3ccSAndroid Build Coastguard Worker void PrintObuHeader(const ObuHeader *header) {
107*77c1e3ccSAndroid Build Coastguard Worker printf(
108*77c1e3ccSAndroid Build Coastguard Worker " OBU type: %s\n"
109*77c1e3ccSAndroid Build Coastguard Worker " extension: %s\n",
110*77c1e3ccSAndroid Build Coastguard Worker aom_obu_type_to_string(static_cast<OBU_TYPE>(header->type)),
111*77c1e3ccSAndroid Build Coastguard Worker header->has_extension ? "yes" : "no");
112*77c1e3ccSAndroid Build Coastguard Worker if (header->has_extension) {
113*77c1e3ccSAndroid Build Coastguard Worker printf(
114*77c1e3ccSAndroid Build Coastguard Worker " temporal_id: %d\n"
115*77c1e3ccSAndroid Build Coastguard Worker " spatial_id: %d\n",
116*77c1e3ccSAndroid Build Coastguard Worker header->temporal_layer_id, header->spatial_layer_id);
117*77c1e3ccSAndroid Build Coastguard Worker }
118*77c1e3ccSAndroid Build Coastguard Worker }
119*77c1e3ccSAndroid Build Coastguard Worker
120*77c1e3ccSAndroid Build Coastguard Worker } // namespace
121*77c1e3ccSAndroid Build Coastguard Worker
DumpObu(const uint8_t * data,int length,int * obu_overhead_bytes)122*77c1e3ccSAndroid Build Coastguard Worker bool DumpObu(const uint8_t *data, int length, int *obu_overhead_bytes) {
123*77c1e3ccSAndroid Build Coastguard Worker const int kObuHeaderSizeBytes = 1;
124*77c1e3ccSAndroid Build Coastguard Worker const int kMinimumBytesRequired = 1 + kObuHeaderSizeBytes;
125*77c1e3ccSAndroid Build Coastguard Worker int consumed = 0;
126*77c1e3ccSAndroid Build Coastguard Worker int obu_overhead = 0;
127*77c1e3ccSAndroid Build Coastguard Worker ObuHeader obu_header;
128*77c1e3ccSAndroid Build Coastguard Worker while (consumed < length) {
129*77c1e3ccSAndroid Build Coastguard Worker const int remaining = length - consumed;
130*77c1e3ccSAndroid Build Coastguard Worker if (remaining < kMinimumBytesRequired) {
131*77c1e3ccSAndroid Build Coastguard Worker fprintf(stderr,
132*77c1e3ccSAndroid Build Coastguard Worker "OBU parse error. Did not consume all data, %d bytes remain.\n",
133*77c1e3ccSAndroid Build Coastguard Worker remaining);
134*77c1e3ccSAndroid Build Coastguard Worker return false;
135*77c1e3ccSAndroid Build Coastguard Worker }
136*77c1e3ccSAndroid Build Coastguard Worker
137*77c1e3ccSAndroid Build Coastguard Worker int obu_header_size = 0;
138*77c1e3ccSAndroid Build Coastguard Worker
139*77c1e3ccSAndroid Build Coastguard Worker memset(&obu_header, 0, sizeof(obu_header));
140*77c1e3ccSAndroid Build Coastguard Worker const uint8_t obu_header_byte = *(data + consumed);
141*77c1e3ccSAndroid Build Coastguard Worker if (!ParseObuHeader(obu_header_byte, &obu_header)) {
142*77c1e3ccSAndroid Build Coastguard Worker fprintf(stderr, "OBU parsing failed at offset %d.\n", consumed);
143*77c1e3ccSAndroid Build Coastguard Worker return false;
144*77c1e3ccSAndroid Build Coastguard Worker }
145*77c1e3ccSAndroid Build Coastguard Worker
146*77c1e3ccSAndroid Build Coastguard Worker ++obu_overhead;
147*77c1e3ccSAndroid Build Coastguard Worker ++obu_header_size;
148*77c1e3ccSAndroid Build Coastguard Worker
149*77c1e3ccSAndroid Build Coastguard Worker if (obu_header.has_extension) {
150*77c1e3ccSAndroid Build Coastguard Worker const uint8_t obu_ext_header_byte =
151*77c1e3ccSAndroid Build Coastguard Worker *(data + consumed + kObuHeaderSizeBytes);
152*77c1e3ccSAndroid Build Coastguard Worker if (!ParseObuExtensionHeader(obu_ext_header_byte, &obu_header)) {
153*77c1e3ccSAndroid Build Coastguard Worker fprintf(stderr, "OBU extension parsing failed at offset %d.\n",
154*77c1e3ccSAndroid Build Coastguard Worker consumed + kObuHeaderSizeBytes);
155*77c1e3ccSAndroid Build Coastguard Worker return false;
156*77c1e3ccSAndroid Build Coastguard Worker }
157*77c1e3ccSAndroid Build Coastguard Worker
158*77c1e3ccSAndroid Build Coastguard Worker ++obu_overhead;
159*77c1e3ccSAndroid Build Coastguard Worker ++obu_header_size;
160*77c1e3ccSAndroid Build Coastguard Worker }
161*77c1e3ccSAndroid Build Coastguard Worker
162*77c1e3ccSAndroid Build Coastguard Worker PrintObuHeader(&obu_header);
163*77c1e3ccSAndroid Build Coastguard Worker
164*77c1e3ccSAndroid Build Coastguard Worker uint64_t obu_size = 0;
165*77c1e3ccSAndroid Build Coastguard Worker size_t length_field_size = 0;
166*77c1e3ccSAndroid Build Coastguard Worker if (aom_uleb_decode(data + consumed + obu_header_size,
167*77c1e3ccSAndroid Build Coastguard Worker remaining - obu_header_size, &obu_size,
168*77c1e3ccSAndroid Build Coastguard Worker &length_field_size) != 0) {
169*77c1e3ccSAndroid Build Coastguard Worker fprintf(stderr, "OBU size parsing failed at offset %d.\n",
170*77c1e3ccSAndroid Build Coastguard Worker consumed + obu_header_size);
171*77c1e3ccSAndroid Build Coastguard Worker return false;
172*77c1e3ccSAndroid Build Coastguard Worker }
173*77c1e3ccSAndroid Build Coastguard Worker int current_obu_length = static_cast<int>(obu_size);
174*77c1e3ccSAndroid Build Coastguard Worker if (obu_header_size + static_cast<int>(length_field_size) +
175*77c1e3ccSAndroid Build Coastguard Worker current_obu_length >
176*77c1e3ccSAndroid Build Coastguard Worker remaining) {
177*77c1e3ccSAndroid Build Coastguard Worker fprintf(stderr, "OBU parsing failed: not enough OBU data.\n");
178*77c1e3ccSAndroid Build Coastguard Worker return false;
179*77c1e3ccSAndroid Build Coastguard Worker }
180*77c1e3ccSAndroid Build Coastguard Worker consumed += obu_header_size + static_cast<int>(length_field_size) +
181*77c1e3ccSAndroid Build Coastguard Worker current_obu_length;
182*77c1e3ccSAndroid Build Coastguard Worker printf(" length: %d\n",
183*77c1e3ccSAndroid Build Coastguard Worker static_cast<int>(obu_header_size + length_field_size +
184*77c1e3ccSAndroid Build Coastguard Worker current_obu_length));
185*77c1e3ccSAndroid Build Coastguard Worker }
186*77c1e3ccSAndroid Build Coastguard Worker
187*77c1e3ccSAndroid Build Coastguard Worker if (obu_overhead_bytes != nullptr) *obu_overhead_bytes = obu_overhead;
188*77c1e3ccSAndroid Build Coastguard Worker printf(" TU size: %d\n", consumed);
189*77c1e3ccSAndroid Build Coastguard Worker
190*77c1e3ccSAndroid Build Coastguard Worker return true;
191*77c1e3ccSAndroid Build Coastguard Worker }
192*77c1e3ccSAndroid Build Coastguard Worker
193*77c1e3ccSAndroid Build Coastguard Worker } // namespace aom_tools
194