| /* | |
| * Copyright © 2018, VideoLAN and dav1d authors | |
| * Copyright © 2018, Two Orioles, LLC | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are met: | |
| * | |
| * 1. Redistributions of source code must retain the above copyright notice, this | |
| * list of conditions and the following disclaimer. | |
| * | |
| * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| * this list of conditions and the following disclaimer in the documentation | |
| * and/or other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| // OBU parsing and bit magic all originally from dav1d's obu.c and getbits.c, | |
| // but heavily modified/reduced down to simply find the Sequence Header OBU | |
| // and pull a few interesting pieces from it. | |
| // | |
| // Any other code in here is under this license: | |
| // | |
| // Copyright 2020 Joe Drago. All rights reserved. | |
| // SPDX-License-Identifier: BSD-2-Clause | |
| #include "avif/internal.h" | |
| #include <stdint.h> | |
| #include <string.h> | |
| #if defined(AVIF_CODEC_AVM) | |
| #include "avm/avm_codec.h" | |
| #endif | |
| // --------------------------------------------------------------------------- | |
| // avifBits - Originally dav1d's GetBits struct (see dav1d's getbits.c) | |
| typedef struct avifBits | |
| { | |
| int error, eof; | |
| uint64_t state; | |
| uint32_t bitsLeft; | |
| const uint8_t *ptr, *start, *end; | |
| } avifBits; | |
| static inline uint32_t avifBitsReadPos(const avifBits * bits) | |
| { | |
| return (uint32_t)(bits->ptr - bits->start) * 8 - bits->bitsLeft; | |
| } | |
| static void avifBitsInit(avifBits * const bits, const uint8_t * const data, const size_t size) | |
| { | |
| bits->ptr = bits->start = data; | |
| bits->end = &bits->start[size]; | |
| bits->bitsLeft = 0; | |
| bits->state = 0; | |
| bits->error = 0; | |
| bits->eof = (size == 0); | |
| } | |
| static void avifBitsRefill(avifBits * const bits, const uint32_t n) | |
| { | |
| uint64_t state = 0; | |
| do { | |
| state <<= 8; | |
| bits->bitsLeft += 8; | |
| if (!bits->eof) | |
| state |= *bits->ptr++; | |
| if (bits->ptr >= bits->end) { | |
| bits->error = bits->eof; | |
| bits->eof = 1; | |
| } | |
| } while (n > bits->bitsLeft); | |
| bits->state |= state << (64 - bits->bitsLeft); | |
| } | |
| static uint32_t avifBitsRead(avifBits * const bits, const uint32_t n) | |
| { | |
| if (n > bits->bitsLeft) | |
| avifBitsRefill(bits, n); | |
| const uint64_t state = bits->state; | |
| bits->bitsLeft -= n; | |
| bits->state <<= n; | |
| return (uint32_t)(state >> (64 - n)); | |
| } | |
| static uint32_t avifBitsReadUleb128(avifBits * bits) | |
| { | |
| uint64_t val = 0; | |
| uint32_t more; | |
| uint32_t i = 0; | |
| do { | |
| const uint32_t v = avifBitsRead(bits, 8); | |
| more = v & 0x80; | |
| val |= ((uint64_t)(v & 0x7F)) << i; | |
| i += 7; | |
| } while (more && i < 56); | |
| if (val > UINT32_MAX || more) { | |
| bits->error = 1; | |
| return 0; | |
| } | |
| return (uint32_t)val; | |
| } | |
| static uint32_t avifBitsReadVLC(avifBits * const bits) | |
| { | |
| int numBits = 0; | |
| while (!avifBitsRead(bits, 1)) | |
| if (++numBits == 32) | |
| return 0xFFFFFFFFU; | |
| return numBits ? ((1U << numBits) - 1) + avifBitsRead(bits, numBits) : 0; | |
| } | |
| #if defined(AVIF_CODEC_AVM) | |
| // Rice-Golomb coding with parameter n. | |
| static uint32_t avifBitsReadRG(avifBits * const bits, const uint32_t n) | |
| { | |
| for (uint32_t q = 0; q < 32; q++) { | |
| const uint32_t rgBit = avifBitsRead(bits, 1); | |
| if (rgBit == 0) { | |
| const uint32_t remainder = avifBitsRead(bits, n); | |
| return (q << n) + remainder; | |
| } | |
| } | |
| return 0xFFFFFFFFU; | |
| } | |
| #endif // defined(AVIF_CODEC_AVM) | |
| // --------------------------------------------------------------------------- | |
| // Variables in here use snake_case to self-document from the AV1 spec and the draft AV2 spec: | |
| // | |
| // https://aomediacodec.github.io/av1-spec/av1-spec.pdf | |
| // | |
| // Originally dav1d's parse_seq_hdr() function (heavily modified and split) | |
| static avifBool parseAV1SequenceHeaderProfile(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| uint32_t seq_profile = avifBitsRead(bits, 3); | |
| if (seq_profile > 2) { | |
| return AVIF_FALSE; | |
| } | |
| header->av1C.seqProfile = (uint8_t)seq_profile; | |
| return !bits->error; | |
| } | |
| #if defined(AVIF_CODEC_AVM) | |
| static avifBool parseAV2SequenceHeaderProfile(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| uint32_t seq_profile = avifBitsRead(bits, 5); | |
| if (seq_profile >= 32) { | |
| return AVIF_FALSE; | |
| } | |
| header->av1C.seqProfile = (uint8_t)seq_profile; | |
| return !bits->error; | |
| } | |
| #endif // defined(AVIF_CODEC_AVM) | |
| static avifBool parseSequenceHeaderLevelIdxAndTier(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| uint32_t still_picture = avifBitsRead(bits, 1); | |
| header->reduced_still_picture_header = (uint8_t)avifBitsRead(bits, 1); | |
| if (header->reduced_still_picture_header && !still_picture) { | |
| return AVIF_FALSE; | |
| } | |
| if (header->reduced_still_picture_header) { | |
| header->av1C.seqLevelIdx0 = (uint8_t)avifBitsRead(bits, 5); | |
| header->av1C.seqTier0 = 0; | |
| } else { | |
| uint32_t timing_info_present_flag = avifBitsRead(bits, 1); | |
| uint32_t decoder_model_info_present_flag = 0; | |
| uint32_t buffer_delay_length = 0; | |
| if (timing_info_present_flag) { // timing_info() | |
| avifBitsRead(bits, 32); // num_units_in_display_tick | |
| avifBitsRead(bits, 32); // time_scale | |
| uint32_t equal_picture_interval = avifBitsRead(bits, 1); | |
| if (equal_picture_interval) { | |
| uint32_t num_ticks_per_picture_minus_1 = avifBitsReadVLC(bits); | |
| if (num_ticks_per_picture_minus_1 == 0xFFFFFFFFU) | |
| return AVIF_FALSE; | |
| } | |
| decoder_model_info_present_flag = avifBitsRead(bits, 1); | |
| if (decoder_model_info_present_flag) { // decoder_model_info() | |
| buffer_delay_length = avifBitsRead(bits, 5) + 1; | |
| avifBitsRead(bits, 32); // num_units_in_decoding_tick | |
| avifBitsRead(bits, 10); // buffer_removal_time_length_minus_1, frame_presentation_time_length_minus_1 | |
| } | |
| } | |
| uint32_t initial_display_delay_present_flag = avifBitsRead(bits, 1); | |
| uint32_t operating_points_cnt = avifBitsRead(bits, 5) + 1; | |
| for (uint32_t i = 0; i < operating_points_cnt; i++) { | |
| avifBitsRead(bits, 12); // operating_point_idc | |
| uint32_t seq_level_idx = avifBitsRead(bits, 5); | |
| if (i == 0) { | |
| header->av1C.seqLevelIdx0 = (uint8_t)seq_level_idx; | |
| header->av1C.seqTier0 = 0; | |
| } | |
| if (seq_level_idx > 7) { | |
| uint32_t seq_tier = avifBitsRead(bits, 1); | |
| if (i == 0) { | |
| header->av1C.seqTier0 = (uint8_t)seq_tier; | |
| } | |
| } | |
| if (decoder_model_info_present_flag) { | |
| uint32_t decoder_model_present_for_this_op = avifBitsRead(bits, 1); | |
| if (decoder_model_present_for_this_op) { // operating_parameters_info() | |
| avifBitsRead(bits, buffer_delay_length); // decoder_buffer_delay | |
| avifBitsRead(bits, buffer_delay_length); // encoder_buffer_delay | |
| avifBitsRead(bits, 1); // low_delay_mode_flag | |
| } | |
| } | |
| if (initial_display_delay_present_flag) { | |
| uint32_t initial_display_delay_present_for_this_op = avifBitsRead(bits, 1); | |
| if (initial_display_delay_present_for_this_op) { | |
| avifBitsRead(bits, 4); // initial_display_delay_minus_1 | |
| } | |
| } | |
| } | |
| } | |
| return !bits->error; | |
| } | |
| static avifBool parseSequenceHeaderFrameMaxDimensions(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| uint32_t frame_width_bits = avifBitsRead(bits, 4) + 1; | |
| uint32_t frame_height_bits = avifBitsRead(bits, 4) + 1; | |
| header->maxWidth = avifBitsRead(bits, frame_width_bits) + 1; // max_frame_width | |
| header->maxHeight = avifBitsRead(bits, frame_height_bits) + 1; // max_frame_height | |
| uint32_t frame_id_numbers_present_flag = 0; | |
| if (!header->reduced_still_picture_header) { | |
| frame_id_numbers_present_flag = avifBitsRead(bits, 1); | |
| } | |
| if (frame_id_numbers_present_flag) { | |
| avifBitsRead(bits, 7); // delta_frame_id_length_minus_2, additional_frame_id_length_minus_1 | |
| } | |
| return !bits->error; | |
| } | |
| static avifBool parseSequenceHeaderEnabledFeatures(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| avifBitsRead(bits, 2); // enable_filter_intra, enable_intra_edge_filter | |
| if (!header->reduced_still_picture_header) { | |
| avifBitsRead(bits, 4); // enable_interintra_compound, enable_masked_compound, enable_warped_motion, enable_dual_filter | |
| uint32_t enable_order_hint = avifBitsRead(bits, 1); | |
| if (enable_order_hint) { | |
| avifBitsRead(bits, 2); // enable_jnt_comp, enable_ref_frame_mvs | |
| } | |
| uint32_t seq_force_screen_content_tools = 0; | |
| uint32_t seq_choose_screen_content_tools = avifBitsRead(bits, 1); | |
| if (seq_choose_screen_content_tools) { | |
| seq_force_screen_content_tools = 2; | |
| } else { | |
| seq_force_screen_content_tools = avifBitsRead(bits, 1); | |
| } | |
| if (seq_force_screen_content_tools > 0) { | |
| uint32_t seq_choose_integer_mv = avifBitsRead(bits, 1); | |
| if (!seq_choose_integer_mv) { | |
| avifBitsRead(bits, 1); // seq_force_integer_mv | |
| } | |
| } | |
| if (enable_order_hint) { | |
| avifBitsRead(bits, 3); // order_hint_bits_minus_1 | |
| } | |
| } | |
| return !bits->error; | |
| } | |
| // Note: Does not parse separate_uv_delta_q. | |
| static avifBool parseAV1SequenceHeaderColorConfig(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| header->bitDepth = 8; | |
| header->chromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN; | |
| header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition; | |
| uint32_t high_bitdepth = avifBitsRead(bits, 1); | |
| header->av1C.highBitdepth = (uint8_t)high_bitdepth; | |
| if ((header->av1C.seqProfile == 2) && high_bitdepth) { | |
| uint32_t twelve_bit = avifBitsRead(bits, 1); | |
| header->bitDepth = twelve_bit ? 12 : 10; | |
| header->av1C.twelveBit = (uint8_t)twelve_bit; | |
| } else /* if (seq_profile <= 2) */ { | |
| header->bitDepth = high_bitdepth ? 10 : 8; | |
| header->av1C.twelveBit = 0; | |
| } | |
| uint32_t mono_chrome = 0; | |
| if (header->av1C.seqProfile != 1) { | |
| mono_chrome = avifBitsRead(bits, 1); | |
| } | |
| header->av1C.monochrome = (uint8_t)mono_chrome; | |
| uint32_t color_description_present_flag = avifBitsRead(bits, 1); | |
| if (color_description_present_flag) { | |
| header->colorPrimaries = (avifColorPrimaries)avifBitsRead(bits, 8); // color_primaries | |
| header->transferCharacteristics = (avifTransferCharacteristics)avifBitsRead(bits, 8); // transfer_characteristics | |
| header->matrixCoefficients = (avifMatrixCoefficients)avifBitsRead(bits, 8); // matrix_coefficients | |
| } else { | |
| header->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; | |
| header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; | |
| header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED; | |
| } | |
| if (mono_chrome) { | |
| header->range = avifBitsRead(bits, 1) ? AVIF_RANGE_FULL : AVIF_RANGE_LIMITED; // color_range | |
| header->av1C.chromaSubsamplingX = 1; | |
| header->av1C.chromaSubsamplingY = 1; | |
| header->yuvFormat = AVIF_PIXEL_FORMAT_YUV400; | |
| } else if (header->colorPrimaries == AVIF_COLOR_PRIMARIES_BT709 && | |
| header->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_SRGB && | |
| header->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_IDENTITY) { | |
| header->range = AVIF_RANGE_FULL; | |
| header->av1C.chromaSubsamplingX = 0; | |
| header->av1C.chromaSubsamplingY = 0; | |
| header->yuvFormat = AVIF_PIXEL_FORMAT_YUV444; | |
| } else { | |
| uint32_t subsampling_x = 0; | |
| uint32_t subsampling_y = 0; | |
| header->range = avifBitsRead(bits, 1) ? AVIF_RANGE_FULL : AVIF_RANGE_LIMITED; // color_range | |
| switch (header->av1C.seqProfile) { | |
| case 0: | |
| subsampling_x = 1; | |
| subsampling_y = 1; | |
| header->yuvFormat = AVIF_PIXEL_FORMAT_YUV420; | |
| break; | |
| case 1: | |
| subsampling_x = 0; | |
| subsampling_y = 0; | |
| header->yuvFormat = AVIF_PIXEL_FORMAT_YUV444; | |
| break; | |
| case 2: | |
| if (header->bitDepth == 12) { | |
| subsampling_x = avifBitsRead(bits, 1); | |
| if (subsampling_x) { | |
| subsampling_y = avifBitsRead(bits, 1); | |
| } | |
| } else { | |
| subsampling_x = 1; | |
| subsampling_y = 0; | |
| } | |
| if (subsampling_x) { | |
| header->yuvFormat = subsampling_y ? AVIF_PIXEL_FORMAT_YUV420 : AVIF_PIXEL_FORMAT_YUV422; | |
| } else { | |
| header->yuvFormat = AVIF_PIXEL_FORMAT_YUV444; | |
| } | |
| break; | |
| default: | |
| return AVIF_FALSE; | |
| } | |
| if (subsampling_x && subsampling_y) { | |
| header->chromaSamplePosition = (avifChromaSamplePosition)avifBitsRead(bits, 2); // chroma_sample_position | |
| header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition; | |
| } | |
| header->av1C.chromaSubsamplingX = (uint8_t)subsampling_x; | |
| header->av1C.chromaSubsamplingY = (uint8_t)subsampling_y; | |
| } | |
| return !bits->error; | |
| } | |
| #if defined(AVIF_CODEC_AVM) | |
| enum | |
| { | |
| AV2_CHROMA_FORMAT_420 = 0, | |
| AV2_CHROMA_FORMAT_400 = 1, | |
| AV2_CHROMA_FORMAT_444 = 2, | |
| AV2_CHROMA_FORMAT_422 = 3, | |
| }; | |
| static avifChromaSamplePosition av2ChromaSamplePositionToAv1ChromaSamplePosition(uint32_t av2ChromaSamplePosition) | |
| { | |
| if (av2ChromaSamplePosition == 0) { | |
| // AVM_CSP_LEFT: Horizontal offset 0, vertical offset 0.5 | |
| return AVIF_CHROMA_SAMPLE_POSITION_VERTICAL; | |
| } else if (av2ChromaSamplePosition == 1) { | |
| // AVM_CSP_CENTER: Horizontal offset 0.5, vertical offset 0.5 | |
| return AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN; | |
| } else if (av2ChromaSamplePosition == 2) { | |
| // AVM_CSP_TOPLEFT: Horizontal offset 0, vertical offset 0 | |
| return AVIF_CHROMA_SAMPLE_POSITION_COLOCATED; | |
| } else { | |
| return AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN; | |
| } | |
| } | |
| static avifBool parseAV2ChromaFormatBitdepth(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| const uint32_t chromaFormatIdc = avifBitsReadVLC(bits); | |
| const uint32_t bitdepthIdx = avifBitsReadVLC(bits); | |
| if (bitdepthIdx == 0) { | |
| header->bitDepth = 10; | |
| } else if (bitdepthIdx == 1) { | |
| header->bitDepth = 8; | |
| } else if (bitdepthIdx == 2) { | |
| header->bitDepth = 12; | |
| } else { | |
| return AVIF_FALSE; | |
| } | |
| header->av1C.highBitdepth = header->bitDepth > 8; | |
| header->av1C.twelveBit = header->bitDepth == 12; | |
| header->av1C.monochrome = chromaFormatIdc == AV2_CHROMA_FORMAT_400; | |
| if (header->av1C.monochrome) { | |
| header->av1C.chromaSubsamplingX = 1; | |
| header->av1C.chromaSubsamplingY = 1; | |
| header->yuvFormat = AVIF_PIXEL_FORMAT_YUV400; | |
| } else if (chromaFormatIdc == AV2_CHROMA_FORMAT_420) { | |
| header->av1C.chromaSubsamplingX = 1; | |
| header->av1C.chromaSubsamplingY = 1; | |
| header->yuvFormat = AVIF_PIXEL_FORMAT_YUV420; | |
| } else if (chromaFormatIdc == AV2_CHROMA_FORMAT_444) { | |
| header->av1C.chromaSubsamplingX = 0; | |
| header->av1C.chromaSubsamplingY = 0; | |
| header->yuvFormat = AVIF_PIXEL_FORMAT_YUV444; | |
| } else if (chromaFormatIdc == AV2_CHROMA_FORMAT_422) { | |
| header->av1C.chromaSubsamplingX = 1; | |
| header->av1C.chromaSubsamplingY = 0; | |
| header->yuvFormat = AVIF_PIXEL_FORMAT_YUV422; | |
| } else { | |
| return AVIF_FALSE; | |
| } | |
| return !bits->error; | |
| } | |
| #endif // defined(AVIF_CODEC_AVM) | |
| static avifBool parseAV1SequenceHeader(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| AVIF_CHECK(parseAV1SequenceHeaderProfile(bits, header)); | |
| AVIF_CHECK(parseSequenceHeaderLevelIdxAndTier(bits, header)); | |
| AVIF_CHECK(parseSequenceHeaderFrameMaxDimensions(bits, header)); | |
| avifBitsRead(bits, 1); // use_128x128_superblock | |
| AVIF_CHECK(parseSequenceHeaderEnabledFeatures(bits, header)); | |
| avifBitsRead(bits, 3); // enable_superres, enable_cdef, enable_restoration | |
| AVIF_CHECK(parseAV1SequenceHeaderColorConfig(bits, header)); | |
| if (!header->av1C.monochrome) { | |
| avifBitsRead(bits, 1); // separate_uv_delta_q | |
| } | |
| avifBitsRead(bits, 1); // film_grain_params_present | |
| return !bits->error; | |
| } | |
| #if defined(AVIF_CODEC_AVM) | |
| static int avifCeilLog2(int x) | |
| { | |
| if (x < 2) | |
| return 0; | |
| int i = 1; | |
| int p = 2; | |
| while (p < x) { | |
| i++; | |
| p <<= 1; | |
| } | |
| return i; | |
| } | |
| // See read_sequence_header_obu() in av2/decoder/obu.c. | |
| static avifBool parseAV2SequenceHeader(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| uint32_t seqHeaderId = avifBitsReadVLC(bits); | |
| if (seqHeaderId >= 16) { | |
| return AVIF_FALSE; | |
| } | |
| AVIF_CHECK(parseAV2SequenceHeaderProfile(bits, header)); | |
| header->reduced_still_picture_header = (uint8_t)avifBitsRead(bits, 1); // single_picture_header_flag | |
| header->av1C.seqLevelIdx0 = (uint8_t)avifBitsRead(bits, 5); | |
| if (header->av1C.seqLevelIdx0 >= 4 && !header->reduced_still_picture_header) { | |
| header->av1C.seqTier0 = avifBitsRead(bits, 1); | |
| } else { | |
| header->av1C.seqTier0 = 0; | |
| } | |
| AVIF_CHECK(parseAV2ChromaFormatBitdepth(bits, header)); | |
| if (!header->reduced_still_picture_header) { | |
| avifBitsRead(bits, 3); // seq_lcr_id | |
| avifBitsRead(bits, 1); // still_picture | |
| avifBitsRead(bits, 2); // max_tlayer_id | |
| const int maxMlayerId = avifBitsRead(bits, 3); // max_mlayer_id | |
| if (maxMlayerId > 0) { | |
| const int n = avifCeilLog2(maxMlayerId + 1); | |
| avifBitsRead(bits, n); // seq_max_mlayer_cnt_minus_1 | |
| } | |
| avifBitsRead(bits, 1); // monotonic_output_order_flag | |
| } | |
| uint32_t frame_width_bits = avifBitsRead(bits, 4) + 1; | |
| uint32_t frame_height_bits = avifBitsRead(bits, 4) + 1; | |
| header->maxWidth = avifBitsRead(bits, frame_width_bits) + 1; // max_frame_width | |
| header->maxHeight = avifBitsRead(bits, frame_height_bits) + 1; // max_frame_height | |
| header->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; | |
| header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; | |
| header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED; | |
| header->range = AVIF_RANGE_LIMITED; | |
| header->chromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN; | |
| header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition; | |
| // Other ignored fields. | |
| return !bits->error; | |
| } | |
| // See av2_read_content_interpretation_obu() in av2/decoder/obu_ci.c. | |
| static avifBool parseAV2ContentInterpretation(avifBits * bits, avifSequenceHeader * header) | |
| { | |
| avifBitsRead(bits, 2); // ci_scan_type_idc | |
| const uint32_t colorDescriptionPresent = avifBitsRead(bits, 1); // ci_color_description_present_flag | |
| const uint32_t chromaSamplePositionPresent = avifBitsRead(bits, 1); // ci_chroma_sample_position_present_flag | |
| avifBitsRead(bits, 1); // ci_aspect_ratio_info_present_flag | |
| avifBitsRead(bits, 1); // ci_timing_info_present_flag | |
| avifBitsRead(bits, 1); // ci_extension_present_flag | |
| avifBitsRead(bits, 1); // reserved_bit | |
| if (colorDescriptionPresent) { | |
| // Override the default CICP values. | |
| const uint32_t colorDescriptionIdc = avifBitsReadRG(bits, 2); // color_description_idc | |
| if (colorDescriptionIdc == 0xFFFFFFFFU) { | |
| return AVIF_FALSE; | |
| } | |
| if (colorDescriptionIdc == 0) { | |
| // Explicitly signaled | |
| header->colorPrimaries = (avifColorPrimaries)avifBitsRead(bits, 8); // color_primaries | |
| header->transferCharacteristics = (avifTransferCharacteristics)avifBitsRead(bits, 8); // transfer_characteristics | |
| header->matrixCoefficients = (avifMatrixCoefficients)avifBitsRead(bits, 8); // matrix_coefficients | |
| } else if (colorDescriptionIdc == 1) { | |
| // BT.709 SDR | |
| header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; // 1 | |
| header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_BT709; // 1 | |
| header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709; // 1 | |
| } else if (colorDescriptionIdc == 2) { | |
| // BT.2100 PQ | |
| header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2100; // 9 | |
| header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_PQ; // 16 | |
| header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL; // 9 | |
| } else if (colorDescriptionIdc == 3) { | |
| // BT.2100 HLG | |
| header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2100; // 9 | |
| header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG; // 18 | |
| header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL; // 9 | |
| } else if (colorDescriptionIdc == 4) { | |
| // sRGB | |
| header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; // 1 | |
| header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; // 13 | |
| header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY; // 0 | |
| } else if (colorDescriptionIdc == 5) { | |
| // sYCC | |
| header->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; // 1 | |
| header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; // 13 | |
| header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT470BG; // 5 | |
| } else { | |
| // Reserved | |
| header->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; // 2 | |
| header->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; // 2 | |
| header->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED; // 2 | |
| } | |
| header->range = avifBitsRead(bits, 1) ? AVIF_RANGE_FULL : AVIF_RANGE_LIMITED; // color_range | |
| } else { | |
| // Keep the default CICP values. | |
| } | |
| if (chromaSamplePositionPresent) { | |
| const uint32_t chromaSamplePosition = avifBitsReadVLC(bits); // ci_chroma_sample_position_0 | |
| header->chromaSamplePosition = av2ChromaSamplePositionToAv1ChromaSamplePosition(chromaSamplePosition); | |
| header->av1C.chromaSamplePosition = (uint8_t)header->chromaSamplePosition; | |
| } | |
| // Other ignored fields. | |
| return !bits->error; | |
| } | |
| #endif // defined(AVIF_CODEC_AVM) | |
| static avifBool av1SequenceHeaderParse(avifSequenceHeader * header, const avifROData * sample) | |
| { | |
| avifROData obus = *sample; | |
| // Find the sequence header OBU | |
| while (obus.size > 0) { | |
| avifBits bits; | |
| avifBitsInit(&bits, obus.data, obus.size); | |
| // obu_header() | |
| const uint32_t obu_forbidden_bit = avifBitsRead(&bits, 1); | |
| if (obu_forbidden_bit != 0) { | |
| return AVIF_FALSE; | |
| } | |
| const uint32_t obu_type = avifBitsRead(&bits, 4); | |
| const uint32_t obu_extension_flag = avifBitsRead(&bits, 1); | |
| const uint32_t obu_has_size_field = avifBitsRead(&bits, 1); | |
| avifBitsRead(&bits, 1); // obu_reserved_1bit | |
| if (obu_extension_flag) { // obu_extension_header() | |
| avifBitsRead(&bits, 8); // temporal_id, spatial_id, extension_header_reserved_3bits | |
| } | |
| uint32_t obu_size = 0; | |
| if (obu_has_size_field) | |
| obu_size = avifBitsReadUleb128(&bits); | |
| else | |
| obu_size = (int)obus.size - 1 - obu_extension_flag; | |
| if (bits.error) { | |
| return AVIF_FALSE; | |
| } | |
| const uint32_t init_bit_pos = avifBitsReadPos(&bits); | |
| const uint32_t init_byte_pos = init_bit_pos >> 3; | |
| if (obu_size > obus.size - init_byte_pos) | |
| return AVIF_FALSE; | |
| if (obu_type == 1) { // Sequence Header | |
| avifBits seqHdrBits; | |
| avifBitsInit(&seqHdrBits, obus.data + init_byte_pos, obu_size); | |
| return parseAV1SequenceHeader(&seqHdrBits, header); | |
| } | |
| // Skip this OBU | |
| obus.data += (size_t)obu_size + init_byte_pos; | |
| obus.size -= (size_t)obu_size + init_byte_pos; | |
| } | |
| return AVIF_FALSE; | |
| } | |
| #if defined(AVIF_CODEC_AVM) | |
| static avifBool av2SequenceHeaderParse(avifSequenceHeader * header, const avifROData * sample) | |
| { | |
| avifBool sequenceHeaderFound = AVIF_FALSE; | |
| avifROData obus = *sample; | |
| // Find the Sequence Header OBU, and the Content Interpretation OBU if any. | |
| while (obus.size > 0) { | |
| avifBits bits; | |
| avifBitsInit(&bits, obus.data, obus.size); | |
| const uint32_t obuSize = avifBitsReadUleb128(&bits); | |
| // obu_header() | |
| const uint32_t obuHeaderExtensionFlag = avifBitsRead(&bits, 1); | |
| const uint32_t obuType = avifBitsRead(&bits, 5); | |
| avifBitsRead(&bits, 2); // obu_tlayer_id | |
| if (obuHeaderExtensionFlag) { | |
| avifBitsRead(&bits, 8); // obu_mlayer_id, obu_xlayer_id | |
| } | |
| if (bits.error) { | |
| return AVIF_FALSE; | |
| } | |
| const uint32_t obuHeaderSize = 1 + obuHeaderExtensionFlag; | |
| if (obuSize < obuHeaderSize) { | |
| return AVIF_FALSE; | |
| } | |
| const uint32_t obuPayloadSize = obuSize - obuHeaderSize; | |
| const uint32_t initBitPos = avifBitsReadPos(&bits); | |
| const uint32_t initBytePos = initBitPos >> 3; | |
| if (obuPayloadSize > obus.size - initBytePos) { | |
| return AVIF_FALSE; | |
| } | |
| if (obuType == OBU_SEQUENCE_HEADER) { | |
| if (sequenceHeaderFound) { | |
| return AVIF_FALSE; | |
| } | |
| avifBits seqHdrBits; | |
| avifBitsInit(&seqHdrBits, obus.data + initBytePos, obuPayloadSize); | |
| if (!parseAV2SequenceHeader(&seqHdrBits, header)) { | |
| return AVIF_FALSE; | |
| } | |
| sequenceHeaderFound = AVIF_TRUE; | |
| } else if (obuType == OBU_CONTENT_INTERPRETATION) { // optional | |
| if (!sequenceHeaderFound) { | |
| return AVIF_FALSE; | |
| } | |
| avifBits ciBits; | |
| avifBitsInit(&ciBits, obus.data + initBytePos, obuPayloadSize); | |
| if (!parseAV2ContentInterpretation(&ciBits, header)) { | |
| return AVIF_FALSE; | |
| } | |
| break; | |
| } | |
| obus.data += (size_t)obuPayloadSize + initBytePos; | |
| obus.size -= (size_t)obuPayloadSize + initBytePos; | |
| } | |
| return sequenceHeaderFound; | |
| } | |
| #endif // defined(AVIF_CODEC_AVM) | |
| avifBool avifSequenceHeaderParse(avifSequenceHeader * header, const avifROData * sample, avifCodecType codecType) | |
| { | |
| switch (codecType) { | |
| case AVIF_CODEC_TYPE_AV1: | |
| return av1SequenceHeaderParse(header, sample); | |
| #if defined(AVIF_CODEC_AVM) | |
| case AVIF_CODEC_TYPE_AV2: | |
| return av2SequenceHeaderParse(header, sample); | |
| #endif | |
| default: | |
| return AVIF_FALSE; | |
| } | |
| } |