Tom Finegan | 1d773ac | 2018-08-21 19:23:04 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2018, 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 | #include <stdio.h> |
| 12 | #include <string.h> |
| 13 | |
| 14 | #include "aom/aom_image.h" |
| 15 | #include "aom/aom_integer.h" |
| 16 | #include "aom_dsp/bitreader_buffer.h" |
| 17 | #include "aom_dsp/bitwriter_buffer.h" |
| 18 | #include "av1/common/obu_util.h" |
| 19 | #include "common/av1_config.h" |
| 20 | #include "config/aom_config.h" |
| 21 | |
| 22 | // Helper macros to reduce verbosity required to check for read errors. |
| 23 | // |
| 24 | // Note that when using these macros, even single line if statements should use |
| 25 | // curly braces to avoid unexpected behavior because all but the |
| 26 | // AV1C_POP_ERROR_HANDLER_DATA() macro consist of multiple statements. |
| 27 | #define AV1C_READ_BIT_OR_RETURN_ERROR(field) \ |
| 28 | int field = 0; \ |
| 29 | do { \ |
| 30 | field = aom_rb_read_bit(reader); \ |
| 31 | if (result == -1) { \ |
| 32 | fprintf(stderr, \ |
| 33 | "av1c: Error reading bit for " #field ", value=%d result=%d.\n", \ |
| 34 | field, result); \ |
| 35 | return -1; \ |
| 36 | } \ |
| 37 | } while (0) |
| 38 | |
| 39 | #define AV1C_READ_BITS_OR_RETURN_ERROR(field, length) \ |
| 40 | int field = 0; \ |
| 41 | do { \ |
| 42 | field = aom_rb_read_literal(reader, (length)); \ |
| 43 | if (result == -1) { \ |
| 44 | fprintf(stderr, \ |
| 45 | "av1c: Could not read bits for " #field \ |
| 46 | ", value=%d result=%d.\n", \ |
| 47 | field, result); \ |
| 48 | return -1; \ |
| 49 | } \ |
| 50 | } while (0) |
| 51 | |
| 52 | // Helper macros for setting/restoring the error handler data in |
| 53 | // aom_read_bit_buffer. |
| 54 | #define AV1C_PUSH_ERROR_HANDLER_DATA(new_data) \ |
| 55 | void *original_error_handler_data = NULL; \ |
| 56 | do { \ |
| 57 | original_error_handler_data = reader->error_handler_data; \ |
| 58 | reader->error_handler_data = &new_data; \ |
| 59 | } while (0) |
| 60 | |
| 61 | #define AV1C_POP_ERROR_HANDLER_DATA() \ |
| 62 | do { \ |
| 63 | reader->error_handler_data = original_error_handler_data; \ |
| 64 | } while (0) |
| 65 | |
| 66 | static const size_t kAv1cSize = 4; |
| 67 | |
| 68 | static void bitreader_error_handler(void *data) { |
| 69 | int *error_val = (int *)data; |
| 70 | *error_val = -1; |
| 71 | } |
| 72 | |
| 73 | // Parse the AV1 timing_info() structure: |
| 74 | // timing_info( ) { |
| 75 | // num_units_in_display_tick f(32) |
| 76 | // time_scale f(32) |
| 77 | // equal_picture_interval f(1) |
| 78 | // if (equal_picture_interval) |
| 79 | // num_ticks_per_picture_minus_1 uvlc() |
| 80 | // } |
| 81 | static int parse_timing_info(struct aom_read_bit_buffer *reader) { |
| 82 | int result = 0; |
| 83 | AV1C_PUSH_ERROR_HANDLER_DATA(result); |
| 84 | |
| 85 | AV1C_READ_BITS_OR_RETURN_ERROR(num_units_in_display_tick, 32); |
| 86 | AV1C_READ_BITS_OR_RETURN_ERROR(time_scale, 32); |
| 87 | |
| 88 | AV1C_READ_BIT_OR_RETURN_ERROR(equal_picture_interval); |
| 89 | if (equal_picture_interval) { |
| 90 | uint32_t num_ticks_per_picture_minus_1 = aom_rb_read_uvlc(reader); |
| 91 | if (result == -1) { |
| 92 | fprintf(stderr, |
| 93 | "av1c: Could not read bits for " |
| 94 | "num_ticks_per_picture_minus_1, value=%u.\n", |
| 95 | num_ticks_per_picture_minus_1); |
| 96 | return result; |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | AV1C_POP_ERROR_HANDLER_DATA(); |
| 101 | return result; |
| 102 | } |
| 103 | |
| 104 | // Parse the AV1 decoder_model_info() structure: |
| 105 | // decoder_model_info( ) { |
| 106 | // buffer_delay_length_minus_1 f(5) |
| 107 | // num_units_in_decoding_tick f(32) |
| 108 | // buffer_removal_time_length_minus_1 f(5) |
| 109 | // frame_presentation_time_length_minus_1 f(5) |
| 110 | // } |
| 111 | // |
| 112 | // Returns -1 upon failure, or the value of buffer_delay_length_minus_1 + 1. |
| 113 | static int parse_decoder_model_info(struct aom_read_bit_buffer *reader) { |
| 114 | int result = 0; |
| 115 | AV1C_PUSH_ERROR_HANDLER_DATA(result); |
| 116 | |
| 117 | AV1C_READ_BITS_OR_RETURN_ERROR(buffer_delay_length_minus_1, 5); |
| 118 | AV1C_READ_BITS_OR_RETURN_ERROR(num_units_in_decoding_tick, 32); |
| 119 | AV1C_READ_BITS_OR_RETURN_ERROR(buffer_removal_time_length_minus_1, 5); |
| 120 | AV1C_READ_BITS_OR_RETURN_ERROR(frame_presentation_time_length_minus_1, 5); |
| 121 | |
| 122 | AV1C_POP_ERROR_HANDLER_DATA(); |
| 123 | return buffer_delay_length_minus_1 + 1; |
| 124 | } |
| 125 | |
| 126 | // Parse the AV1 operating_parameters_info() structure: |
| 127 | // operating_parameters_info( op ) { |
| 128 | // n = buffer_delay_length_minus_1 + 1 |
| 129 | // decoder_buffer_delay[ op ] f(n) |
| 130 | // encoder_buffer_delay[ op ] f(n) |
| 131 | // low_delay_mode_flag[ op ] f(1) |
| 132 | // } |
| 133 | static int parse_operating_parameters_info(struct aom_read_bit_buffer *reader, |
| 134 | int buffer_delay_length_minus_1) { |
| 135 | int result = 0; |
| 136 | AV1C_PUSH_ERROR_HANDLER_DATA(result); |
| 137 | |
| 138 | const int buffer_delay_length = buffer_delay_length_minus_1 + 1; |
| 139 | AV1C_READ_BITS_OR_RETURN_ERROR(decoder_buffer_delay, buffer_delay_length); |
| 140 | AV1C_READ_BITS_OR_RETURN_ERROR(encoder_buffer_delay, buffer_delay_length); |
| 141 | AV1C_READ_BIT_OR_RETURN_ERROR(low_delay_mode_flag); |
| 142 | |
| 143 | AV1C_POP_ERROR_HANDLER_DATA(); |
| 144 | return result; |
| 145 | } |
| 146 | |
| 147 | // Parse the AV1 color_config() structure..See: |
| 148 | // https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=44 |
| 149 | static int parse_color_config(struct aom_read_bit_buffer *reader, |
| 150 | Av1Config *config) { |
| 151 | int result = 0; |
| 152 | AV1C_PUSH_ERROR_HANDLER_DATA(result); |
| 153 | |
| 154 | AV1C_READ_BIT_OR_RETURN_ERROR(high_bitdepth); |
| 155 | config->high_bitdepth = high_bitdepth; |
| 156 | |
| 157 | int bit_depth = 0; |
| 158 | if (config->seq_profile == 2 && config->high_bitdepth) { |
| 159 | AV1C_READ_BIT_OR_RETURN_ERROR(twelve_bit); |
| 160 | config->twelve_bit = twelve_bit; |
| 161 | bit_depth = config->twelve_bit ? 12 : 10; |
| 162 | } else { |
| 163 | bit_depth = config->high_bitdepth ? 10 : 8; |
| 164 | } |
| 165 | |
| 166 | if (config->seq_profile != 1) { |
| 167 | AV1C_READ_BIT_OR_RETURN_ERROR(mono_chrome); |
| 168 | config->monochrome = mono_chrome; |
| 169 | } |
| 170 | |
| 171 | int color_primaries = AOM_CICP_CP_UNSPECIFIED; |
| 172 | int transfer_characteristics = AOM_CICP_TC_UNSPECIFIED; |
| 173 | int matrix_coefficients = AOM_CICP_MC_UNSPECIFIED; |
| 174 | |
| 175 | AV1C_READ_BIT_OR_RETURN_ERROR(color_description_present_flag); |
| 176 | if (color_description_present_flag) { |
| 177 | AV1C_READ_BITS_OR_RETURN_ERROR(color_primaries_val, 8); |
| 178 | color_primaries = color_primaries_val; |
| 179 | AV1C_READ_BITS_OR_RETURN_ERROR(transfer_characteristics_val, 8); |
| 180 | transfer_characteristics = transfer_characteristics_val; |
| 181 | AV1C_READ_BITS_OR_RETURN_ERROR(matrix_coefficients_val, 8); |
| 182 | matrix_coefficients = matrix_coefficients_val; |
| 183 | } |
| 184 | |
| 185 | if (config->monochrome) { |
| 186 | AV1C_READ_BIT_OR_RETURN_ERROR(color_range); |
| 187 | config->chroma_subsampling_x = 1; |
| 188 | config->chroma_subsampling_y = 1; |
| 189 | } else if (color_primaries == AOM_CICP_CP_BT_709 && |
| 190 | transfer_characteristics == AOM_CICP_TC_SRGB && |
| 191 | matrix_coefficients == AOM_CICP_MC_IDENTITY) { |
| 192 | config->chroma_subsampling_x = 0; |
| 193 | config->chroma_subsampling_y = 0; |
| 194 | } else { |
| 195 | AV1C_READ_BIT_OR_RETURN_ERROR(color_range); |
| 196 | if (config->seq_profile == 0) { |
| 197 | config->chroma_subsampling_x = 1; |
| 198 | config->chroma_subsampling_y = 1; |
| 199 | } else if (config->seq_profile == 1) { |
| 200 | config->chroma_subsampling_x = 0; |
| 201 | config->chroma_subsampling_y = 0; |
| 202 | } else { |
| 203 | if (bit_depth == 12) { |
| 204 | AV1C_READ_BIT_OR_RETURN_ERROR(subsampling_x); |
| 205 | config->chroma_subsampling_x = subsampling_x; |
| 206 | if (subsampling_x) { |
| 207 | AV1C_READ_BIT_OR_RETURN_ERROR(subsampling_y); |
| 208 | config->chroma_subsampling_y = subsampling_y; |
| 209 | } else { |
| 210 | config->chroma_subsampling_y = 0; |
| 211 | } |
| 212 | } else { |
| 213 | config->chroma_subsampling_x = 1; |
| 214 | config->chroma_subsampling_y = 0; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | if (config->chroma_subsampling_x && config->chroma_subsampling_y) { |
| 219 | AV1C_READ_BITS_OR_RETURN_ERROR(chroma_sample_position, 2); |
| 220 | config->chroma_sample_position = chroma_sample_position; |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | if (!config->monochrome) { |
| 225 | AV1C_READ_BIT_OR_RETURN_ERROR(separate_uv_delta_q); |
| 226 | } |
| 227 | |
| 228 | AV1C_POP_ERROR_HANDLER_DATA(); |
| 229 | return result; |
| 230 | } |
| 231 | |
| 232 | // Parse AV1 Sequence Header OBU. See: |
| 233 | // https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=41 |
| 234 | static int parse_sequence_header(const uint8_t *const buffer, size_t length, |
| 235 | Av1Config *config) { |
| 236 | int result = 0; |
| 237 | // The reader instance is local to this function, but a pointer to the |
| 238 | // reader instance is used within this function and throughout this file to |
| 239 | // allow use of the helper macros that reduce parse error checking verbosity. |
Hien Ho | 830b897 | 2019-04-04 15:51:14 -0700 | [diff] [blame] | 240 | struct aom_read_bit_buffer reader_instance = { buffer, buffer + length, 0, |
| 241 | &result, |
| 242 | bitreader_error_handler }; |
Tom Finegan | 1d773ac | 2018-08-21 19:23:04 -0700 | [diff] [blame] | 243 | struct aom_read_bit_buffer *reader = &reader_instance; |
| 244 | |
| 245 | AV1C_READ_BITS_OR_RETURN_ERROR(seq_profile, 3); |
| 246 | config->seq_profile = seq_profile; |
| 247 | AV1C_READ_BIT_OR_RETURN_ERROR(still_picture); |
| 248 | AV1C_READ_BIT_OR_RETURN_ERROR(reduced_still_picture_header); |
| 249 | if (reduced_still_picture_header) { |
| 250 | config->initial_presentation_delay_present = 0; |
| 251 | AV1C_READ_BITS_OR_RETURN_ERROR(seq_level_idx_0, 5); |
| 252 | config->seq_level_idx_0 = seq_level_idx_0; |
| 253 | config->seq_tier_0 = 0; |
| 254 | } else { |
| 255 | int has_decoder_model = 0; |
| 256 | int buffer_delay_length = 0; |
| 257 | |
| 258 | AV1C_READ_BIT_OR_RETURN_ERROR(timing_info_present_flag); |
| 259 | if (timing_info_present_flag) { |
| 260 | if (parse_timing_info(reader) != 0) return -1; |
| 261 | |
| 262 | AV1C_READ_BIT_OR_RETURN_ERROR(decoder_model_info_present_flag); |
| 263 | if (decoder_model_info_present_flag && |
| 264 | (buffer_delay_length = parse_decoder_model_info(reader)) == -1) { |
| 265 | return -1; |
| 266 | } |
| 267 | has_decoder_model = 1; |
| 268 | } |
| 269 | |
| 270 | AV1C_READ_BIT_OR_RETURN_ERROR(initial_presentation_delay_present); |
| 271 | config->initial_presentation_delay_present = |
| 272 | initial_presentation_delay_present; |
| 273 | |
| 274 | AV1C_READ_BITS_OR_RETURN_ERROR(operating_points_cnt_minus_1, 5); |
| 275 | const int num_operating_points = operating_points_cnt_minus_1 + 1; |
| 276 | |
| 277 | for (int op_index = 0; op_index < num_operating_points; ++op_index) { |
| 278 | AV1C_READ_BITS_OR_RETURN_ERROR(operating_point_idc, 12); |
| 279 | AV1C_READ_BITS_OR_RETURN_ERROR(seq_level_idx, 5); |
| 280 | |
| 281 | int seq_tier = 0; |
| 282 | if (seq_level_idx > 7) { |
| 283 | AV1C_READ_BIT_OR_RETURN_ERROR(seq_tier_this_op); |
| 284 | seq_tier = seq_tier_this_op; |
| 285 | } |
| 286 | |
| 287 | if (has_decoder_model) { |
| 288 | AV1C_READ_BIT_OR_RETURN_ERROR(decoder_model_present_for_op); |
| 289 | if (decoder_model_present_for_op) { |
| 290 | if (parse_operating_parameters_info(reader, buffer_delay_length) == |
| 291 | -1) { |
| 292 | return -1; |
| 293 | } |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | if (config->initial_presentation_delay_present) { |
| 298 | // Skip the initial presentation delay bits if present since this |
| 299 | // function has no access to the data required to properly set the |
| 300 | // field. |
| 301 | AV1C_READ_BIT_OR_RETURN_ERROR( |
| 302 | initial_presentation_delay_present_for_this_op); |
| 303 | if (initial_presentation_delay_present_for_this_op) { |
| 304 | AV1C_READ_BITS_OR_RETURN_ERROR(initial_presentation_delay_minus_1, 4); |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | if (op_index == 0) { |
| 309 | // Av1Config needs only the values from the first operating point. |
| 310 | config->seq_level_idx_0 = seq_level_idx; |
| 311 | config->seq_tier_0 = seq_tier; |
| 312 | config->initial_presentation_delay_present = 0; |
| 313 | config->initial_presentation_delay_minus_one = 0; |
| 314 | } |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | AV1C_READ_BITS_OR_RETURN_ERROR(frame_width_bits_minus_1, 4); |
| 319 | AV1C_READ_BITS_OR_RETURN_ERROR(frame_height_bits_minus_1, 4); |
| 320 | AV1C_READ_BITS_OR_RETURN_ERROR(max_frame_width_minus_1, |
| 321 | frame_width_bits_minus_1 + 1); |
| 322 | AV1C_READ_BITS_OR_RETURN_ERROR(max_frame_height_minus_1, |
| 323 | frame_height_bits_minus_1 + 1); |
| 324 | |
Yaowu Xu | 0f268b6 | 2019-01-02 15:39:48 -0800 | [diff] [blame] | 325 | uint8_t frame_id_numbers_present = 0; |
Tom Finegan | 1d773ac | 2018-08-21 19:23:04 -0700 | [diff] [blame] | 326 | if (!reduced_still_picture_header) { |
| 327 | AV1C_READ_BIT_OR_RETURN_ERROR(frame_id_numbers_present_flag); |
| 328 | frame_id_numbers_present = frame_id_numbers_present_flag; |
| 329 | } |
| 330 | |
| 331 | if (frame_id_numbers_present) { |
| 332 | AV1C_READ_BITS_OR_RETURN_ERROR(delta_frame_id_length_minus_2, 4); |
| 333 | AV1C_READ_BITS_OR_RETURN_ERROR(additional_frame_id_length_minus_1, 3); |
| 334 | } |
| 335 | |
| 336 | AV1C_READ_BIT_OR_RETURN_ERROR(use_128x128_superblock); |
| 337 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_filter_intra); |
| 338 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_intra_edge_filter); |
| 339 | |
| 340 | if (!reduced_still_picture_header) { |
| 341 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_interintra_compound); |
| 342 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_masked_compound); |
| 343 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_warped_motion); |
| 344 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_dual_filter); |
| 345 | |
| 346 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_order_hint); |
| 347 | if (enable_order_hint) { |
Debargha Mukherjee | 0c96c11 | 2018-12-20 16:04:18 -0800 | [diff] [blame] | 348 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_dist_wtd_comp); |
Tom Finegan | 1d773ac | 2018-08-21 19:23:04 -0700 | [diff] [blame] | 349 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_ref_frame_mvs); |
| 350 | } |
| 351 | |
| 352 | const int SELECT_SCREEN_CONTENT_TOOLS = 2; |
| 353 | int seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS; |
| 354 | AV1C_READ_BIT_OR_RETURN_ERROR(seq_choose_screen_content_tools); |
| 355 | if (!seq_choose_screen_content_tools) { |
| 356 | AV1C_READ_BIT_OR_RETURN_ERROR(seq_force_screen_content_tools_val); |
| 357 | seq_force_screen_content_tools = seq_force_screen_content_tools_val; |
| 358 | } |
| 359 | |
| 360 | if (seq_force_screen_content_tools > 0) { |
| 361 | AV1C_READ_BIT_OR_RETURN_ERROR(seq_choose_integer_mv); |
| 362 | |
| 363 | if (!seq_choose_integer_mv) { |
| 364 | AV1C_READ_BIT_OR_RETURN_ERROR(seq_force_integer_mv); |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | if (enable_order_hint) { |
| 369 | AV1C_READ_BITS_OR_RETURN_ERROR(order_hint_bits_minus_1, 3); |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_superres); |
| 374 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_cdef); |
| 375 | AV1C_READ_BIT_OR_RETURN_ERROR(enable_restoration); |
| 376 | |
| 377 | if (parse_color_config(reader, config) != 0) { |
| 378 | fprintf(stderr, "av1c: color_config() parse failed.\n"); |
| 379 | return -1; |
| 380 | } |
| 381 | |
| 382 | AV1C_READ_BIT_OR_RETURN_ERROR(film_grain_params_present); |
| 383 | return 0; |
| 384 | } |
| 385 | |
Wan-Teh Chang | 4137f7d | 2018-09-07 09:54:23 -0700 | [diff] [blame] | 386 | int get_av1config_from_obu(const uint8_t *buffer, size_t length, int is_annexb, |
| 387 | Av1Config *config) { |
Tom Finegan | 1d773ac | 2018-08-21 19:23:04 -0700 | [diff] [blame] | 388 | if (!buffer || length == 0 || !config) { |
| 389 | return -1; |
| 390 | } |
| 391 | |
| 392 | ObuHeader obu_header; |
| 393 | memset(&obu_header, 0, sizeof(obu_header)); |
| 394 | |
| 395 | size_t sequence_header_length = 0; |
| 396 | size_t obu_header_length = 0; |
| 397 | if (aom_read_obu_header_and_size(buffer, length, is_annexb, &obu_header, |
| 398 | &sequence_header_length, |
| 399 | &obu_header_length) != AOM_CODEC_OK || |
| 400 | obu_header.type != OBU_SEQUENCE_HEADER || |
| 401 | sequence_header_length + obu_header_length > length) { |
| 402 | return -1; |
| 403 | } |
| 404 | |
| 405 | memset(config, 0, sizeof(*config)); |
| 406 | config->marker = 1; |
| 407 | config->version = 1; |
| 408 | return parse_sequence_header(buffer + obu_header_length, |
| 409 | sequence_header_length, config); |
| 410 | } |
| 411 | |
Wan-Teh Chang | 4137f7d | 2018-09-07 09:54:23 -0700 | [diff] [blame] | 412 | int read_av1config(const uint8_t *buffer, size_t buffer_length, |
Tom Finegan | 1d773ac | 2018-08-21 19:23:04 -0700 | [diff] [blame] | 413 | size_t *bytes_read, Av1Config *config) { |
| 414 | if (!buffer || buffer_length < kAv1cSize || !bytes_read || !config) return -1; |
| 415 | |
| 416 | *bytes_read = 0; |
| 417 | |
| 418 | int result = 0; |
Hien Ho | 830b897 | 2019-04-04 15:51:14 -0700 | [diff] [blame] | 419 | struct aom_read_bit_buffer reader_instance = { buffer, buffer + buffer_length, |
| 420 | 0, &result, |
| 421 | bitreader_error_handler }; |
Tom Finegan | 1d773ac | 2018-08-21 19:23:04 -0700 | [diff] [blame] | 422 | struct aom_read_bit_buffer *reader = &reader_instance; |
| 423 | |
| 424 | memset(config, 0, sizeof(*config)); |
| 425 | |
| 426 | AV1C_READ_BIT_OR_RETURN_ERROR(marker); |
| 427 | config->marker = marker; |
| 428 | |
| 429 | AV1C_READ_BITS_OR_RETURN_ERROR(version, 7); |
| 430 | config->version = version; |
| 431 | |
| 432 | AV1C_READ_BITS_OR_RETURN_ERROR(seq_profile, 3); |
| 433 | config->seq_profile = seq_profile; |
| 434 | |
| 435 | AV1C_READ_BITS_OR_RETURN_ERROR(seq_level_idx_0, 5); |
| 436 | config->seq_level_idx_0 = seq_level_idx_0; |
| 437 | |
| 438 | AV1C_READ_BIT_OR_RETURN_ERROR(seq_tier_0); |
| 439 | config->seq_tier_0 = seq_tier_0; |
| 440 | |
| 441 | AV1C_READ_BIT_OR_RETURN_ERROR(high_bitdepth); |
| 442 | config->high_bitdepth = high_bitdepth; |
| 443 | |
| 444 | AV1C_READ_BIT_OR_RETURN_ERROR(twelve_bit); |
| 445 | config->twelve_bit = twelve_bit; |
| 446 | |
| 447 | AV1C_READ_BIT_OR_RETURN_ERROR(monochrome); |
| 448 | config->monochrome = monochrome; |
| 449 | |
| 450 | AV1C_READ_BIT_OR_RETURN_ERROR(chroma_subsampling_x); |
| 451 | config->chroma_subsampling_x = chroma_subsampling_x; |
| 452 | |
| 453 | AV1C_READ_BIT_OR_RETURN_ERROR(chroma_subsampling_y); |
| 454 | config->chroma_subsampling_y = chroma_subsampling_y; |
| 455 | |
| 456 | AV1C_READ_BITS_OR_RETURN_ERROR(chroma_sample_position, 2); |
| 457 | config->chroma_sample_position = chroma_sample_position; |
| 458 | |
| 459 | AV1C_READ_BITS_OR_RETURN_ERROR(reserved, 3); |
| 460 | |
| 461 | AV1C_READ_BIT_OR_RETURN_ERROR(initial_presentation_delay_present); |
| 462 | config->initial_presentation_delay_present = |
| 463 | initial_presentation_delay_present; |
| 464 | |
| 465 | AV1C_READ_BITS_OR_RETURN_ERROR(initial_presentation_delay_minus_one, 4); |
| 466 | config->initial_presentation_delay_minus_one = |
| 467 | initial_presentation_delay_minus_one; |
| 468 | |
| 469 | *bytes_read = aom_rb_bytes_read(reader); |
| 470 | |
| 471 | return 0; |
| 472 | } |
| 473 | |
Wan-Teh Chang | 4137f7d | 2018-09-07 09:54:23 -0700 | [diff] [blame] | 474 | int write_av1config(const Av1Config *config, size_t capacity, |
Tom Finegan | 1d773ac | 2018-08-21 19:23:04 -0700 | [diff] [blame] | 475 | size_t *bytes_written, uint8_t *buffer) { |
| 476 | if (!config || !buffer || capacity < kAv1cSize || !bytes_written) return -1; |
| 477 | |
| 478 | *bytes_written = 0; |
| 479 | memset(buffer, 0, kAv1cSize); |
| 480 | |
| 481 | struct aom_write_bit_buffer writer = { buffer, 0 }; |
| 482 | |
| 483 | aom_wb_write_bit(&writer, config->marker); |
| 484 | aom_wb_write_literal(&writer, config->version, 7); |
| 485 | aom_wb_write_literal(&writer, config->seq_profile, 3); |
| 486 | aom_wb_write_literal(&writer, config->seq_level_idx_0, 5); |
| 487 | aom_wb_write_bit(&writer, config->seq_tier_0); |
| 488 | aom_wb_write_bit(&writer, config->high_bitdepth); |
| 489 | aom_wb_write_bit(&writer, config->twelve_bit); |
| 490 | aom_wb_write_bit(&writer, config->monochrome); |
| 491 | aom_wb_write_bit(&writer, config->chroma_subsampling_x); |
| 492 | aom_wb_write_bit(&writer, config->chroma_subsampling_y); |
| 493 | aom_wb_write_literal(&writer, config->chroma_sample_position, 2); |
| 494 | aom_wb_write_literal(&writer, 0, 3); // reserved |
| 495 | aom_wb_write_bit(&writer, config->initial_presentation_delay_present); |
| 496 | |
| 497 | if (config->initial_presentation_delay_present) { |
| 498 | aom_wb_write_literal(&writer, config->initial_presentation_delay_minus_one, |
| 499 | 4); |
| 500 | } else { |
| 501 | aom_wb_write_literal(&writer, 0, 4); // reserved |
| 502 | } |
| 503 | |
| 504 | *bytes_written = aom_wb_bytes_written(&writer); |
| 505 | return 0; |
| 506 | } |
| 507 | |
| 508 | #undef AV1C_READ_BIT_OR_RETURN_ERROR |
| 509 | #undef AV1C_READ_BITS_OR_RETURN_ERROR |
| 510 | #undef AV1C_PUSH_ERROR_HANDLER_DATA |
| 511 | #undef AV1C_POP_ERROR_HANDLER_DATA |