Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 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 | |
| 12 | #include <stdio.h> |
| 13 | #include <stdlib.h> |
| 14 | #include <string.h> |
| 15 | |
| 16 | #include "./obudec.h" |
| 17 | |
| 18 | #include "aom_ports/mem_ops.h" |
| 19 | #include "av1/common/common.h" |
| 20 | |
| 21 | #define OBU_HEADER_SIZE_BYTES 1 |
Soo-Chul Han | f858986 | 2018-01-24 03:13:14 +0000 | [diff] [blame] | 22 | #define OBU_HEADER_EXTENSION_SIZE_BYTES 1 |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 23 | |
| 24 | #if CONFIG_OBU_SIZING |
| 25 | // Unsigned LEB128 OBU length field has maximum size of 8 bytes. |
| 26 | #define OBU_MAX_LENGTH_FIELD_SIZE 8 |
| 27 | #define OBU_MAX_HEADER_SIZE \ |
| 28 | (OBU_HEADER_SIZE_BYTES + OBU_HEADER_EXTENSION_SIZE_BYTES + \ |
| 29 | OBU_MAX_LENGTH_FIELD_SIZE) |
| 30 | #else |
| 31 | #define OBU_MAX_LENGTH_FIELD_SIZE PRE_OBU_SIZE_BYTES |
| 32 | #define OBU_MAX_HEADER_SIZE \ |
| 33 | (OBU_HEADER_SIZE_BYTES + OBU_HEADER_EXTENSION_SIZE_BYTES + PRE_OBU_SIZE_BYTES) |
Soo-Chul Han | f858986 | 2018-01-24 03:13:14 +0000 | [diff] [blame] | 34 | #endif |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 35 | |
| 36 | #if CONFIG_OBU_NO_IVF |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 37 | int read_obu_type(uint8_t obu_header, OBU_TYPE *obu_type) { |
| 38 | if (!obu_type) return -1; |
| 39 | const int obu_type_value = (obu_header >> 3) & 0xF; |
| 40 | switch (obu_type_value) { |
| 41 | case OBU_SEQUENCE_HEADER: *obu_type = OBU_SEQUENCE_HEADER; break; |
| 42 | case OBU_TEMPORAL_DELIMITER: *obu_type = OBU_TEMPORAL_DELIMITER; break; |
| 43 | case OBU_FRAME_HEADER: *obu_type = OBU_FRAME_HEADER; break; |
| 44 | case OBU_TILE_GROUP: *obu_type = OBU_TILE_GROUP; break; |
| 45 | case OBU_METADATA: *obu_type = OBU_METADATA; break; |
| 46 | case OBU_PADDING: *obu_type = OBU_PADDING; break; |
| 47 | default: return -1; |
| 48 | } |
| 49 | return 0; |
| 50 | } |
| 51 | |
| 52 | // Reads OBU size from infile and returns 0 upon success. Returns obu_size via |
| 53 | // output pointer obu_size. Returns -1 when reading or parsing fails. Always |
| 54 | // returns FILE pointer to position at time of call. Returns 0 and sets obu_size |
| 55 | // to 0 when end of file is reached. |
| 56 | int read_obu_size(FILE *infile, uint64_t *obu_size, size_t *length_field_size) { |
| 57 | if (!infile || !obu_size) return 1; |
| 58 | |
| 59 | uint8_t read_buffer[OBU_MAX_LENGTH_FIELD_SIZE] = { 0 }; |
| 60 | size_t bytes_read = fread(read_buffer, 1, OBU_MAX_LENGTH_FIELD_SIZE, infile); |
| 61 | *obu_size = 0; |
| 62 | |
| 63 | if (bytes_read == 0) { |
| 64 | return 0; |
| 65 | } |
| 66 | |
| 67 | const int seek_pos = (int)bytes_read; |
| 68 | if (seek_pos != 0 && fseek(infile, -seek_pos, SEEK_CUR) != 0) return 1; |
| 69 | |
| 70 | #if CONFIG_OBU_SIZING |
| 71 | if (aom_uleb_decode(read_buffer, bytes_read, obu_size, length_field_size) != |
| 72 | 0) { |
| 73 | return 1; |
| 74 | } |
| 75 | #else |
| 76 | if (length_field_size) *length_field_size = PRE_OBU_SIZE_BYTES; |
| 77 | *obu_size = mem_get_le32(read_buffer); |
| 78 | #endif |
| 79 | |
| 80 | return 0; |
| 81 | } |
| 82 | |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 83 | int obu_read_temporal_unit(FILE *infile, uint8_t **buffer, size_t *bytes_read, |
Soo-Chul Han | f858986 | 2018-01-24 03:13:14 +0000 | [diff] [blame] | 84 | #if CONFIG_SCALABILITY |
| 85 | size_t *buffer_size, int last_layer_id) { |
| 86 | #else |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 87 | size_t *buffer_size) { |
Soo-Chul Han | f858986 | 2018-01-24 03:13:14 +0000 | [diff] [blame] | 88 | #endif |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 89 | size_t ret; |
Hui Su | e19c321 | 2018-02-21 14:32:18 -0800 | [diff] [blame] | 90 | uint64_t obu_size = 0; |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 91 | uint8_t *data = NULL; |
| 92 | |
| 93 | if (feof(infile)) { |
| 94 | return 1; |
| 95 | } |
| 96 | |
| 97 | *buffer_size = 0; |
| 98 | *bytes_read = 0; |
| 99 | while (1) { |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 100 | size_t length_field_size = 0; |
| 101 | ret = read_obu_size(infile, &obu_size, &length_field_size); |
| 102 | if (ret != 0) { |
| 103 | warn("Failed to read OBU size.\n"); |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 104 | return 1; |
| 105 | } |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 106 | if (ret == 0 && obu_size == 0) { |
| 107 | fprintf(stderr, "Found end of stream, ending temporal unit\n"); |
| 108 | break; |
| 109 | } |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 110 | |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 111 | obu_size += length_field_size; |
| 112 | |
| 113 | // Expand the buffer to contain the full OBU and its length. |
| 114 | const uint8_t *old_buffer = *buffer; |
Yaowu Xu | 6d4fee3 | 2018-02-27 14:38:34 -0800 | [diff] [blame] | 115 | *buffer = (uint8_t *)realloc(*buffer, *buffer_size + (size_t)obu_size); |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 116 | if (!*buffer) { |
| 117 | free((void *)old_buffer); |
| 118 | warn("OBU buffer alloc failed.\n"); |
| 119 | return 1; |
| 120 | } |
| 121 | |
| 122 | data = *buffer + (*buffer_size); |
| 123 | *buffer_size += obu_size; |
Yaowu Xu | 6d4fee3 | 2018-02-27 14:38:34 -0800 | [diff] [blame] | 124 | ret = fread(data, 1, (size_t)obu_size, infile); |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 125 | |
| 126 | if (ret != obu_size) { |
| 127 | warn("Failed to read OBU.\n"); |
| 128 | return 1; |
| 129 | } |
| 130 | *bytes_read += obu_size; |
| 131 | |
| 132 | OBU_TYPE obu_type; |
| 133 | if (read_obu_type(data[length_field_size], &obu_type) != 0) { |
| 134 | warn("Invalid OBU type.\n"); |
| 135 | return 1; |
| 136 | } |
| 137 | |
| 138 | if (obu_type == OBU_TEMPORAL_DELIMITER) { |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 139 | // Stop when a temporal delimiter is found |
| 140 | // fprintf(stderr, "Found temporal delimiter, ending temporal unit\n"); |
| 141 | // prevent decoder to start decoding another frame from this buffer |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 142 | *bytes_read -= obu_size; |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 143 | break; |
| 144 | } |
| 145 | |
Soo-Chul Han | f858986 | 2018-01-24 03:13:14 +0000 | [diff] [blame] | 146 | #if CONFIG_SCALABILITY |
| 147 | // break if obu_extension_flag is found and enhancement_id change |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 148 | if (data[length_field_size] & 0x1) { |
| 149 | const uint8_t obu_extension_header = |
| 150 | data[length_field_size + OBU_HEADER_SIZE_BYTES]; |
| 151 | const int curr_layer_id = (obu_extension_header >> 3) & 0x3; |
Soo-Chul Han | f858986 | 2018-01-24 03:13:14 +0000 | [diff] [blame] | 152 | if (curr_layer_id && (curr_layer_id > last_layer_id)) { |
| 153 | // new enhancement layer |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 154 | *bytes_read -= obu_size; |
| 155 | const int i_obu_size = (int)obu_size; |
| 156 | fseek(infile, -i_obu_size, SEEK_CUR); |
Soo-Chul Han | f858986 | 2018-01-24 03:13:14 +0000 | [diff] [blame] | 157 | break; |
Soo-Chul Han | f858986 | 2018-01-24 03:13:14 +0000 | [diff] [blame] | 158 | } |
| 159 | } |
| 160 | #endif |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 161 | } |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 162 | |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 163 | return 0; |
| 164 | } |
| 165 | |
| 166 | int file_is_obu(struct AvxInputContext *input_ctx) { |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 167 | uint8_t obutd[OBU_MAX_HEADER_SIZE] = { 0 }; |
| 168 | uint64_t size = 0; |
| 169 | |
| 170 | // Parsing of Annex B OBU streams via pipe without framing not supported. This |
| 171 | // implementation requires seeking backwards in the input stream. Tell caller |
| 172 | // that this input cannot be processed. |
| 173 | if (!input_ctx->filename || strcmp(input_ctx->filename, "-") == 0) return 0; |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 174 | |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 175 | // Reading the first OBU TD to enable TU end detection at TD start. |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 176 | const size_t ret = fread(obutd, 1, OBU_MAX_HEADER_SIZE, input_ctx->file); |
| 177 | if (ret != OBU_MAX_HEADER_SIZE) { |
| 178 | warn("Failed to read OBU Header, not enough data to process header.\n"); |
Hui Su | e19c321 | 2018-02-21 14:32:18 -0800 | [diff] [blame] | 179 | return 0; |
| 180 | } |
Tom Finegan | 41150ad | 2018-01-23 11:42:55 -0800 | [diff] [blame] | 181 | |
| 182 | #if CONFIG_OBU_SIZING |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 183 | if (aom_uleb_decode(obutd, OBU_MAX_HEADER_SIZE, &size, NULL) != 0) { |
| 184 | warn("OBU size parse failed.\n"); |
| 185 | return 0; |
| 186 | } |
| 187 | const size_t obu_header_offset = aom_uleb_size_in_bytes(size); |
Tom Finegan | 41150ad | 2018-01-23 11:42:55 -0800 | [diff] [blame] | 188 | #else |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 189 | const size_t obu_header_offset = PRE_OBU_SIZE_BYTES; |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 190 | size = mem_get_le32(obutd); |
Tom Finegan | 41150ad | 2018-01-23 11:42:55 -0800 | [diff] [blame] | 191 | #endif // CONFIG_OBU_SIZING |
| 192 | |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 193 | fseek(input_ctx->file, obu_header_offset + OBU_HEADER_SIZE_BYTES, SEEK_SET); |
Soo-Chul Han | f858986 | 2018-01-24 03:13:14 +0000 | [diff] [blame] | 194 | |
Tom Finegan | ccb8cc4 | 2018-02-22 14:08:13 -0800 | [diff] [blame] | 195 | if (size != 1) { |
| 196 | warn("Expected first OBU size to be 1, got %d\n", size); |
| 197 | return 0; |
| 198 | } |
| 199 | OBU_TYPE obu_type; |
| 200 | if (read_obu_type(obutd[obu_header_offset], &obu_type) != 0) { |
| 201 | warn("Invalid OBU type found while probing for OBU_TEMPORAL_DELIMITER.\n"); |
| 202 | return 0; |
| 203 | } |
| 204 | if (obu_type != OBU_TEMPORAL_DELIMITER) { |
| 205 | warn("Expected OBU TD at file start, got %d\n", obutd[obu_header_offset]); |
| 206 | return 0; |
| 207 | } |
| 208 | |
| 209 | // fprintf(stderr, "Starting to parse OBU stream\n"); |
Cyril Concolato | 6c78883 | 2017-10-30 16:30:35 -0700 | [diff] [blame] | 210 | return 1; |
| 211 | } |
| 212 | |
| 213 | #endif |