vlc | branch: master | Francois Cartegnie <[email protected]> | Wed Sep 26 14:36:53 2018 +0200| [e9be573ff0ad162ac2ac545b7cbff491a102e4ad] | committer: Francois Cartegnie
packetizer: add AV1 helpers > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e9be573ff0ad162ac2ac545b7cbff491a102e4ad --- modules/packetizer/av1.h | 30 +++ modules/packetizer/av1_obu.c | 588 +++++++++++++++++++++++++++++++++++++++++++ modules/packetizer/av1_obu.h | 237 +++++++++++++++++ 3 files changed, 855 insertions(+) diff --git a/modules/packetizer/av1.h b/modules/packetizer/av1.h new file mode 100644 index 0000000000..932670352e --- /dev/null +++ b/modules/packetizer/av1.h @@ -0,0 +1,30 @@ +/***************************************************************************** + * av1.h: AV1 definitions + ***************************************************************************** + * Copyright (C) 2018 VideoLabs, VLC authors and VideoLAN + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ +#ifndef VLC_AV1_H +#define VLC_AV1_H + +enum av1_profile_e +{ + AV1_PROFILE_MAIN = 0, + AV1_PROFILE_HIGH = 1, + AV1_PROFILE_PROFESSIONNAL = 2, +}; + +#endif diff --git a/modules/packetizer/av1_obu.c b/modules/packetizer/av1_obu.c new file mode 100644 index 0000000000..4f60ced230 --- /dev/null +++ b/modules/packetizer/av1_obu.c @@ -0,0 +1,588 @@ +/***************************************************************************** + * av1_obu.c: AV1 OBU parser + ***************************************************************************** + * Copyright (C) 2018 VideoLabs, VLC authors and VideoLAN + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <vlc_common.h> +#include <vlc_bits.h> +#include <vlc_es.h> + +#include "av1.h" +#include "av1_obu.h" +#include "iso_color_tables.h" + +#include <assert.h> + +typedef uint8_t obu_u1_t; +typedef uint8_t obu_u2_t; +typedef uint8_t obu_u3_t; +typedef uint8_t obu_u4_t; +typedef uint8_t obu_u5_t; +typedef uint8_t obu_u6_t; +typedef uint8_t obu_u7_t; +typedef uint8_t obu_u8_t; +typedef uint16_t obu_u12_t; +typedef uint32_t obu_u32_t; +typedef uint32_t obu_uvlc_t; + +#define SELECT_SCREEN_CONTENT_TOOLS 2 +#define SELECT_INTEGER_MV 2 + + +#define AV1_OPERATING_POINTS_COUNT 32 + +/* + * Header + */ +struct av1_header_info_s +{ + obu_u4_t obu_type; + obu_u3_t temporal_id; + obu_u2_t spatial_id; +}; + +static bool av1_read_header(bs_t *p_bs, struct av1_header_info_s *p_hdr) +{ + if(bs_read1(p_bs)) + return false; + p_hdr->obu_type = bs_read(p_bs, 4); + const obu_u1_t obu_extension_flag = bs_read1(p_bs); + const obu_u1_t obu_has_size_field = bs_read1(p_bs); + if(bs_read1(p_bs)) + return false; + if(obu_extension_flag) + { + if(bs_remain(p_bs) < 8) + return false; + p_hdr->temporal_id = bs_read(p_bs, 3); + p_hdr->spatial_id = bs_read(p_bs, 2); + bs_skip(p_bs, 3); + } + if(obu_has_size_field) + { + for (uint8_t i = 0; i < 8; i++) + { + if(bs_remain(p_bs) < 8) + return false; + uint8_t v = bs_read(p_bs, 8); + if (!(v & 0x80)) + break; + if(i == 7) + return false; + } + } + return true; +} + +/* + * Sequence sub sections readers + */ + +struct av1_timing_info_s +{ + obu_u32_t num_units_in_display_tick; + obu_u32_t time_scale; + obu_u1_t equal_picture_interval; + obu_uvlc_t num_ticks_per_picture_minus_1; +}; + +static bool av1_parse_timing_info(bs_t *p_bs, struct av1_timing_info_s *p_ti) +{ + p_ti->num_units_in_display_tick = bs_read(p_bs, 32); + p_ti->time_scale = bs_read(p_bs, 32); + p_ti->equal_picture_interval = bs_read1(p_bs); + if(p_ti->equal_picture_interval) + p_ti->num_ticks_per_picture_minus_1 = bs_read_ue(p_bs); + return true; +} + +struct av1_decoder_model_info_s +{ + obu_u5_t buffer_delay_length_minus_1; + obu_u32_t num_units_in_decoding_tick; + obu_u5_t buffer_removal_time_length_minus_1; + obu_u5_t frame_presentation_time_length_minus_1; +}; + +static bool av1_parse_decoder_model_info(bs_t *p_bs, struct av1_decoder_model_info_s *p_dm) +{ + p_dm->buffer_delay_length_minus_1 = bs_read(p_bs, 5); + p_dm->num_units_in_decoding_tick = bs_read(p_bs, 32); + p_dm->buffer_removal_time_length_minus_1 = bs_read(p_bs, 5); + p_dm->frame_presentation_time_length_minus_1 = bs_read(p_bs, 5); + return true; +} + +struct av1_operating_parameters_info_s +{ + obu_u32_t decoder_buffer_delay; + obu_u32_t encoder_buffer_delay; + obu_u1_t low_delay_mode_flag; +}; + +static bool av1_parse_operating_parameters_info(bs_t *p_bs, + struct av1_operating_parameters_info_s *p_op, + obu_u8_t buffer_delay_length_minus_1) +{ + p_op->decoder_buffer_delay = bs_read(p_bs, 1 + buffer_delay_length_minus_1); + p_op->encoder_buffer_delay = bs_read(p_bs, 1 + buffer_delay_length_minus_1); + p_op->low_delay_mode_flag = bs_read1(p_bs); + return true; +} + +struct av1_color_config_s +{ + obu_u1_t high_bitdepth; + obu_u1_t twelve_bit; + obu_u1_t mono_chrome; + obu_u1_t color_description_present_flag; + obu_u8_t color_primaries; + obu_u8_t transfer_characteristics; + obu_u8_t matrix_coefficients; + obu_u1_t color_range; + obu_u1_t subsampling_x; + obu_u1_t subsampling_y; + obu_u2_t chroma_sample_position; + obu_u1_t separate_uv_delta_q; +}; + +static bool av1_parse_color_config(bs_t *p_bs, + struct av1_color_config_s *p_cc, + obu_u3_t seq_profile) +{ + p_cc->high_bitdepth = bs_read1(p_bs); + if(seq_profile <= 2) + { + if(p_cc->high_bitdepth) + p_cc->twelve_bit = bs_read1(p_bs); + if(seq_profile != 1) + p_cc->mono_chrome = bs_read1(p_bs); + } + const uint8_t BitDepth = p_cc->twelve_bit ? 12 : ((p_cc->high_bitdepth) ? 10 : 8); + + p_cc->color_description_present_flag = bs_read1(p_bs); + if(p_cc->color_description_present_flag) + { + p_cc->color_primaries = bs_read(p_bs, 8); + p_cc->transfer_characteristics = bs_read(p_bs, 8); + p_cc->matrix_coefficients = bs_read(p_bs, 8); + } + else + { + p_cc->color_primaries = 2; + p_cc->transfer_characteristics = 2; + p_cc->matrix_coefficients = 2; + } + + if(p_cc->mono_chrome) + { + p_cc->color_range = bs_read1(p_bs); + } + else if( p_cc->color_primaries == 1 && + p_cc->transfer_characteristics == 13 && + p_cc->matrix_coefficients == 0 ) + { + p_cc->color_range = 1; + } + else + { + p_cc->color_range = bs_read1(p_bs); + if(seq_profile > 1) + { + if(BitDepth == 12) + { + p_cc->subsampling_x = bs_read1(p_bs); + if(p_cc->subsampling_x) + p_cc->subsampling_y = bs_read1(p_bs); + } + else + { + p_cc->subsampling_x = 1; + } + } + if(p_cc->subsampling_x && p_cc->subsampling_y) + p_cc->chroma_sample_position = bs_read(p_bs, 2); + } + + p_cc->separate_uv_delta_q = bs_read1(p_bs); + + return true; +} + +/* + * OBU readers + */ + +struct av1_OBU_sequence_header_t +{ + struct av1_header_info_s obu_header; + obu_u3_t seq_profile; + obu_u1_t still_picture; + obu_u1_t reduced_still_picture_header; + obu_u1_t timing_info_present_flag; + struct av1_timing_info_s timing_info; + obu_u1_t decoder_model_info_present_flag; + struct av1_decoder_model_info_s decoder_model_info; + obu_u1_t initial_display_delay_present_flag; + obu_u1_t operating_points_cnt_minus_1; + struct + { + obu_u12_t operating_point_idc; + obu_u5_t seq_level_idx; + obu_u1_t seq_tier; + obu_u1_t decoder_model_present_for_this_op; + struct av1_operating_parameters_info_s operating_parameters_info; + obu_u1_t initial_display_delay_present_for_this_op; + obu_u4_t initial_display_delay_minus_1; + } operating_points[AV1_OPERATING_POINTS_COUNT]; + obu_u32_t max_frame_width_minus_1; + obu_u32_t max_frame_height_minus_1; + obu_u1_t frame_id_numbers_present_flag; + obu_u4_t delta_frame_id_length_minus_2; + obu_u3_t additional_frame_id_length_minus_1; + obu_u1_t use_128x128_superblock; + obu_u1_t enable_filter_intra; + obu_u1_t enable_intra_edge_filter; + + obu_u1_t enable_interintra_compound; + obu_u1_t enable_masked_compound; + obu_u1_t enable_warped_motion; + obu_u1_t enable_dual_filter; + obu_u1_t enable_order_hint; + obu_u1_t enable_jnt_comp; + obu_u1_t enable_ref_frame_mvs; + obu_u2_t seq_force_screen_content_tools; + obu_u2_t seq_force_integer_mv; + obu_u3_t order_hint_bits_minus_1; + + obu_u1_t enable_superres; + obu_u1_t enable_cdef; + obu_u1_t enable_restoration; + struct av1_color_config_s color_config; + obu_u1_t film_grain_params_present; +}; + +void AV1_release_sequence_header(av1_OBU_sequence_header_t *p_seq) +{ + free(p_seq); +} + +av1_OBU_sequence_header_t * + AV1_OBU_parse_sequence_header(const uint8_t *p_data, size_t i_data) +{ + bs_t bs; + bs_init(&bs, p_data, i_data); + + av1_OBU_sequence_header_t *p_seq = calloc(1, sizeof(*p_seq)); + if(!p_seq) + return NULL; + + if(!av1_read_header(&bs, &p_seq->obu_header)) + { + AV1_release_sequence_header(p_seq); + return NULL; + } + + p_seq->seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS; + p_seq->seq_force_integer_mv = SELECT_INTEGER_MV; + + + p_seq->seq_profile = bs_read(&bs, 3); + p_seq->still_picture = bs_read1(&bs); + const obu_u1_t reduced_still_picture_header = bs_read1(&bs); + if(reduced_still_picture_header) + { + p_seq->operating_points[0].seq_level_idx = bs_read(&bs, 5); + } + else + { + p_seq->timing_info_present_flag = bs_read1(&bs); + if(p_seq->timing_info_present_flag) + { + av1_parse_timing_info(&bs, &p_seq->timing_info); + p_seq->decoder_model_info_present_flag = bs_read1(&bs); + if(p_seq->decoder_model_info_present_flag) + av1_parse_decoder_model_info(&bs, &p_seq->decoder_model_info); + } + + p_seq->initial_display_delay_present_flag = bs_read1(&bs); + p_seq->operating_points_cnt_minus_1 = bs_read(&bs, 5); + for(obu_u5_t i=0; i<=p_seq->operating_points_cnt_minus_1; i++) + { + p_seq->operating_points[i].operating_point_idc = bs_read(&bs, 12); + p_seq->operating_points[i].seq_level_idx = bs_read(&bs, 5); + if(p_seq->operating_points[i].seq_level_idx > 7) + p_seq->operating_points[i].seq_tier = bs_read1(&bs); + if(p_seq->decoder_model_info_present_flag) + { + p_seq->operating_points[i].decoder_model_present_for_this_op = bs_read1(&bs); + if(p_seq->operating_points[i].decoder_model_present_for_this_op) + av1_parse_operating_parameters_info(&bs, &p_seq->operating_points[i].operating_parameters_info, + p_seq->decoder_model_info.buffer_delay_length_minus_1); + } + if(p_seq->initial_display_delay_present_flag) + { + p_seq->operating_points[i].initial_display_delay_present_for_this_op = bs_read1(&bs); + if(p_seq->operating_points[i].initial_display_delay_present_for_this_op) + { + p_seq->operating_points[i].initial_display_delay_minus_1 = bs_read(&bs, 4); + } + } + } + } + const obu_u4_t frame_width_bits_minus_1 = bs_read(&bs, 4); + const obu_u4_t frame_height_bits_minus_1 = bs_read(&bs, 4); + p_seq->max_frame_width_minus_1 = bs_read(&bs, 1 + frame_width_bits_minus_1); + p_seq->max_frame_height_minus_1 = bs_read(&bs, 1 + frame_height_bits_minus_1); + if(!reduced_still_picture_header) + { + p_seq->frame_id_numbers_present_flag = bs_read1(&bs); + if(p_seq->frame_id_numbers_present_flag) + { + p_seq->delta_frame_id_length_minus_2 = bs_read(&bs, 4); + p_seq->additional_frame_id_length_minus_1 = bs_read(&bs, 3); + } + } + p_seq->use_128x128_superblock = bs_read1(&bs); + p_seq->enable_filter_intra = bs_read1(&bs); + p_seq->enable_intra_edge_filter = bs_read1(&bs); + if(!reduced_still_picture_header) + { + p_seq->enable_interintra_compound = bs_read1(&bs); + p_seq->enable_masked_compound = bs_read1(&bs); + p_seq->enable_warped_motion = bs_read1(&bs); + p_seq->enable_dual_filter = bs_read1(&bs); + p_seq->enable_order_hint = bs_read1(&bs); + if(p_seq->enable_order_hint) + { + p_seq->enable_jnt_comp = bs_read1(&bs); + p_seq->enable_ref_frame_mvs = bs_read1(&bs); + } + const obu_u1_t seq_choose_screen_content_tools = bs_read1(&bs); + if(!seq_choose_screen_content_tools) + p_seq->seq_force_screen_content_tools = bs_read1(&bs); + + if(p_seq->seq_force_screen_content_tools) + { + const obu_u1_t seq_choose_integer_mv = bs_read1(&bs); + if(!seq_choose_integer_mv) + p_seq->seq_force_integer_mv = bs_read1(&bs); + } + + if(p_seq->enable_order_hint) + p_seq->order_hint_bits_minus_1 = bs_read(&bs, 3); + } + p_seq->enable_superres = bs_read1(&bs); + p_seq->enable_cdef = bs_read1(&bs); + p_seq->enable_restoration = bs_read1(&bs); + av1_parse_color_config(&bs, &p_seq->color_config, p_seq->seq_profile); + if(bs_remain(&bs) < 1) + { + AV1_release_sequence_header(p_seq); + return NULL; + } + p_seq->film_grain_params_present = bs_read1(&bs); + + return p_seq; +} + +/* + * Frame sub readers + */ + +struct av1_uncompressed_header_s +{ + obu_u1_t show_existing_frame; + obu_u2_t frame_type; + obu_u1_t show_frame; + obu_u32_t frame_presentation_time; +}; + +static bool av1_parse_uncompressed_header(bs_t *p_bs, struct av1_uncompressed_header_s *p_uh, + const av1_OBU_sequence_header_t *p_seq) +{ + if(p_seq->reduced_still_picture_header) + { + p_uh->frame_type = AV1_KEY_FRAME; + p_uh->show_frame = 1; + } + else + { + p_uh->show_existing_frame = bs_read1(p_bs); + if(p_uh->show_existing_frame) + { + const obu_u3_t frame_to_show_map_idx = bs_read(p_bs, 3); + VLC_UNUSED(frame_to_show_map_idx); + if(p_seq->decoder_model_info_present_flag && !p_seq->timing_info.equal_picture_interval) + { + /* temporal_point_info() */ + p_uh->frame_presentation_time = + bs_read(p_bs, 1 + p_seq->decoder_model_info.frame_presentation_time_length_minus_1); + } + if(p_seq->frame_id_numbers_present_flag) + { + const uint8_t idLen = p_seq->additional_frame_id_length_minus_1 + + p_seq->delta_frame_id_length_minus_2 + 3; + const obu_u32_t display_frame_id = bs_read(p_bs, idLen); + VLC_UNUSED(display_frame_id); + } + if(p_seq->film_grain_params_present) + { + /* load_grain */ + } + } + p_uh->frame_type = bs_read(p_bs, 2); + p_uh->show_frame = bs_read1(p_bs); + } + + return true; +} + +/* + * Frame OBU + */ + +struct av1_OBU_frame_header_t +{ + struct av1_header_info_s obu_header; + struct av1_uncompressed_header_s header; +}; + +void AV1_release_frame_header(av1_OBU_frame_header_t *p_fh) +{ + free(p_fh); +} + +av1_OBU_frame_header_t * + AV1_OBU_parse_frame_header(const uint8_t *p_data, size_t i_data, + const av1_OBU_sequence_header_t *p_seq) +{ + bs_t bs; + bs_init(&bs, p_data, i_data); + + av1_OBU_frame_header_t *p_fh = calloc(1, sizeof(*p_fh)); + if(!p_fh) + return NULL; + + if(!av1_read_header(&bs, &p_fh->obu_header) || + !av1_parse_uncompressed_header(&bs, &p_fh->header, p_seq)) + { + AV1_release_frame_header(p_fh); + return NULL; + } + + return p_fh; +} + +enum av1_frame_type_e AV1_get_frame_type(const av1_OBU_frame_header_t *p_fh) +{ + return p_fh->header.frame_type; +} + +bool AV1_get_frame_visibility(const av1_OBU_frame_header_t *p_fh) +{ + return p_fh->header.show_frame; +} + +/* + * Getters + */ +void AV1_get_frame_max_dimensions(const av1_OBU_sequence_header_t *p_seq, unsigned *w, unsigned *h) +{ + *h = 1 + p_seq->max_frame_height_minus_1; + *w = 1 + p_seq->max_frame_width_minus_1; +} + +void AV1_get_profile_level(const av1_OBU_sequence_header_t *p_seq, + int *pi_profile, int *pi_level, int *pi_tier) +{ + *pi_profile = p_seq->seq_profile; + *pi_level = p_seq->operating_points[0].seq_level_idx; + *pi_tier = p_seq->operating_points[0].seq_tier; +} + +bool AV1_get_frame_rate(const av1_OBU_sequence_header_t *p_seq, + unsigned *num, unsigned *den) +{ + if(!p_seq->timing_info_present_flag || + !p_seq->timing_info.equal_picture_interval) /* need support for VFR */ + return false; + *num = (1 + p_seq->timing_info.num_ticks_per_picture_minus_1) * + p_seq->timing_info.num_units_in_display_tick; + *den = p_seq->timing_info.time_scale; + return true; +} + +bool AV1_get_colorimetry(const av1_OBU_sequence_header_t *p_seq, + video_color_primaries_t *p_primaries, + video_transfer_func_t *p_transfer, + video_color_space_t *p_colorspace, + bool *p_full_range) +{ + if(!p_seq->color_config.color_description_present_flag) + return false; + *p_primaries = iso_23001_8_cp_to_vlc_primaries(p_seq->color_config.color_primaries); + *p_transfer = iso_23001_8_tc_to_vlc_xfer(p_seq->color_config.transfer_characteristics); + *p_colorspace = iso_23001_8_mc_to_vlc_coeffs(p_seq->color_config.matrix_coefficients); + *p_full_range = p_seq->color_config.color_range; + return true; +} + +size_t AV1_create_DecoderConfigurationRecord(uint8_t **pp_buffer, + const av1_OBU_sequence_header_t *p_seq, + size_t i_obu, const uint8_t *p_obus[], + const size_t pi_obus[]) +{ + size_t i_buffer = 4; + for(size_t i=0; i<i_obu; i++) + i_buffer += pi_obus[i]; + + uint8_t *p_buffer = malloc(i_buffer); + if(!p_buffer) + return 0; + + bs_t bs; + bs_write_init(&bs, p_buffer, i_buffer); + bs_write(&bs, 1, 1); /* unsigned int (1) marker = 1; */ + bs_write(&bs, 7, 1); /* unsigned int (7) version = 1; */ + bs_write(&bs, 3, p_seq->seq_profile); /* unsigned int (3) seq_profile; */ + bs_write(&bs, 5, p_seq->operating_points[0].seq_level_idx); /* unsigned int (5) seq_level_idx_0; */ + + bs_write(&bs, 1, p_seq->operating_points[0].seq_tier); /* unsigned int (1) seq_tier_0; */ + bs_write(&bs, 1, p_seq->color_config.high_bitdepth); /* unsigned int (1) high_bitdepth; */ + bs_write(&bs, 1, p_seq->color_config.twelve_bit); /* unsigned int (1) twelve_bit; */ + bs_write(&bs, 1, p_seq->color_config.mono_chrome); /* unsigned int (1) monochrome; */ + bs_write(&bs, 1, p_seq->color_config.subsampling_x); /* unsigned int (1) chroma_subsampling_x; */ + bs_write(&bs, 1, p_seq->color_config.subsampling_y); /* unsigned int (1) chroma_subsampling_y; */ + bs_write(&bs, 2, p_seq->color_config.chroma_sample_position); /* unsigned int (2) chroma_sample_position; */ + + bs_write(&bs, 3, 0); /* unsigned int (3) reserved = 0; */ + bs_write(&bs, 1, 0); /* unsigned int (1) initial_presentation_delay_present; (can't compute it) */ + bs_write(&bs, 4, 0); /* unsigned int (4) reserved = 0; */ + + /*unsigned int (8)[] configOBUs;*/ + size_t i_offset = 4; + for(size_t i=0; i<i_obu; i++) + memcpy(&p_buffer[i_offset], p_obus[i], pi_obus[i]); + + *pp_buffer = p_buffer; + return i_buffer; +} diff --git a/modules/packetizer/av1_obu.h b/modules/packetizer/av1_obu.h new file mode 100644 index 0000000000..f9fe1f5c2f --- /dev/null +++ b/modules/packetizer/av1_obu.h @@ -0,0 +1,237 @@ +/***************************************************************************** + * av1_obu: AV1 OBU parser + ***************************************************************************** + * Copyright (C) 2018 VideoLabs, VLC authors and VideoLAN + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ +#ifndef VLC_AV1_OBU_H +#define VLC_AV1_OBU_H + +static inline uint64_t leb128(const uint8_t *p_buf, size_t i_buf, uint8_t *pi_len) +{ + uint64_t i_val = 0; + *pi_len = 0; + for(size_t i=0; i<8; i++) + { + if(i >= i_buf) + break; + i_val |= ((p_buf[i] & 0x7F) << (i * 7)); + if((p_buf[i] & 0x80) == 0) + { + *pi_len = i + 1; + break; + } + } + return *pi_len ? i_val : 0; +} + +enum av1_obu_type_e +{ + AV1_OBU_RESERVED_0 = 0, + AV1_OBU_SEQUENCE_HEADER = 1, + AV1_OBU_TEMPORAL_DELIMITER = 2, + AV1_OBU_FRAME_HEADER = 3, + AV1_OBU_TILE_GROUP = 4, + AV1_OBU_METADATA = 5, + AV1_OBU_FRAME = 6, + AV1_OBU_REDUNDANT_FRAME_HEADER = 7, + AV1_OBU_TILE_LIST = 8, + AV1_OBU_RESERVED_START_9 = 9, + AV1_OBU_RESERVED_END_14 = 14, + AV1_OBU_PADDING = 15, +}; + +static inline enum av1_obu_type_e AV1_OBUGetType(const uint8_t *p_buf) +{ + return (p_buf[0] >> 3) & 0x0F; +} + +static inline bool AV1_OBUHasSizeField(const uint8_t *p_buf) +{ + return p_buf[0] & 0x02; +} + +static inline bool AV1_OBUHasExtensionField(const uint8_t *p_buf) +{ + return p_buf[0] & 0x04; +} + +static inline bool AV1_OBUIsValid(const uint8_t *p_buf, size_t i_buf) +{ + return (i_buf > 0 && (p_buf[0] & 0x81) == 0); +} + +static inline bool AV1_OBUIsBaseLayer(const uint8_t *p_buf, size_t i_buf) +{ + return !AV1_OBUHasExtensionField(p_buf) || (i_buf < 2) || !(p_buf[1] >> 3); +} + +static uint32_t AV1_OBUSize(const uint8_t *p_buf, size_t i_buf, uint8_t *pi_len) +{ + if(!AV1_OBUHasSizeField(p_buf)) + { + if(AV1_OBUHasExtensionField(p_buf) && i_buf < 2) + return false; + return i_buf - 1 - AV1_OBUHasExtensionField(p_buf); + } + + if(AV1_OBUHasExtensionField(p_buf)) + { + if(i_buf == 1) + { + *pi_len = 0; + return 0; + } + /* skip extension header */ + p_buf += 1; + i_buf -= 1; + } + uint64_t i_size = leb128(&p_buf[1], i_buf - 1, pi_len); + if(i_size > (INT64_C(1) << 32) - 1) + { + *pi_len = 0; + return 0; + } + return i_size; +} + +static bool AV1_OBUSkipHeader(const uint8_t **pp_buf, size_t *pi_buf) +{ + if(*pi_buf < 1) + return false; + size_t i_header; + if(AV1_OBUHasSizeField(*pp_buf)) + { + uint8_t i_len; + (void) AV1_OBUSize(*pp_buf, *pi_buf, &i_len); + if(i_len == 0) + return false; + i_header = 1 + !!AV1_OBUHasExtensionField(*pp_buf) + i_len; + } + if(i_header > *pi_buf) + return false; + *pp_buf += i_header; + *pi_buf -= i_header; + return true; +} + +/* METADATA properties */ +enum av1_obu_metadata_type_e +{ + AV1_METADATA_TYPE_RESERVED = 0, + AV1_METADATA_TYPE_HDR_CLL = 1, + AV1_METADATA_TYPE_HDR_MDCV = 2, + AV1_METADATA_TYPE_SCALABILITY = 3, + AV1_METADATA_TYPE_ITUT_T35 = 4, + AV1_METADATA_TYPE_TIMECODE = 5, + AV1_METADATA_TYPE_USER_PRIVATE_START_6 = 6, + AV1_METADATA_TYPE_USER_PRIVATE_END_31 = 31, + AV1_METADATA_TYPE_RESERVED_START_32 = 32, +}; + +static inline enum av1_obu_metadata_type_e + AV1_OBUGetMetadataType(const uint8_t *p_buf, size_t i_buf) +{ + if(!AV1_OBUSkipHeader(&p_buf, &i_buf) || i_buf < 1) + return AV1_METADATA_TYPE_RESERVED; + + uint8_t i_len; + uint64_t i_type = leb128(p_buf, i_buf, &i_len); + if(i_len == 0 || i_type > ((INT64_C(1) << 32) - 1)) + return AV1_METADATA_TYPE_RESERVED; + return i_type; +} + + + +/* SEQUENCE_HEADER properties */ +typedef struct av1_OBU_sequence_header_t av1_OBU_sequence_header_t; +av1_OBU_sequence_header_t * AV1_OBU_parse_sequence_header(const uint8_t *, size_t); +void AV1_release_sequence_header(av1_OBU_sequence_header_t *); +void AV1_get_frame_max_dimensions(const av1_OBU_sequence_header_t *, unsigned *, unsigned *); +void AV1_get_profile_level(const av1_OBU_sequence_header_t *, int *, int *, int *); +bool AV1_get_colorimetry( const av1_OBU_sequence_header_t *, + video_color_primaries_t *, video_transfer_func_t *, + video_color_space_t *, bool *); +bool AV1_get_frame_rate(const av1_OBU_sequence_header_t *, unsigned *, unsigned *); + + + +/* FRAME_HEADER properties */ +typedef struct av1_OBU_frame_header_t av1_OBU_frame_header_t; +enum av1_frame_type_e +{ + AV1_KEY_FRAME = 0, + AV1_INTER_FRAME = 1, + AV1_INTRA_ONLY_FRAME = 2, + AV1_SWITCH_FRAME = 3, +}; + +av1_OBU_frame_header_t * AV1_OBU_parse_frame_header(const uint8_t *p_data, size_t i_data, + const av1_OBU_sequence_header_t *); +void AV1_release_frame_header(av1_OBU_frame_header_t *); +enum av1_frame_type_e AV1_get_frame_type(const av1_OBU_frame_header_t *); +bool AV1_get_frame_visibility(const av1_OBU_frame_header_t *); + + + +/* ISOBMFF Mapping */ + +size_t AV1_create_DecoderConfigurationRecord(uint8_t **, + const av1_OBU_sequence_header_t *, + size_t, const uint8_t *[], const size_t []); + +/* OBU Iterator */ + +typedef struct +{ + const uint8_t *p_head; + const uint8_t *p_tail; +} AV1_OBU_iterator_ctx_t; + +static inline void AV1_OBU_iterator_init(AV1_OBU_iterator_ctx_t *p_ctx, + const uint8_t *p_data, size_t i_data) +{ + p_ctx->p_head = p_data; + p_ctx->p_tail = p_data + i_data; +} + +static inline bool AV1_OBU_iterate_next(AV1_OBU_iterator_ctx_t *p_ctx, + const uint8_t **pp_start, size_t *pi_size) +{ + const size_t i_remain = p_ctx->p_tail - p_ctx->p_head; + if(!AV1_OBUIsValid(p_ctx->p_head, i_remain)) + return false; + if(!AV1_OBUHasSizeField(p_ctx->p_head)) + { + *pp_start = p_ctx->p_head; + *pi_size = i_remain; + p_ctx->p_head = p_ctx->p_tail; + return true; + } + + uint8_t i_obu_size_len; + const uint32_t i_obu_size = AV1_OBUSize(p_ctx->p_head, i_remain, &i_obu_size_len); + const size_t i_obu = i_obu_size + i_obu_size_len + !!AV1_OBUHasExtensionField(p_ctx->p_head) + 1; + if(i_obu_size_len == 0 || i_obu > i_remain) + return false; + *pi_size = i_obu; + *pp_start = p_ctx->p_head; + p_ctx->p_head += i_obu; + return true; +} + +#endif _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
