diff options
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/ffmpeg/A02-hevcmux.patch | 1411 |
1 files changed, 1411 insertions, 0 deletions
diff --git a/contrib/ffmpeg/A02-hevcmux.patch b/contrib/ffmpeg/A02-hevcmux.patch new file mode 100644 index 000000000..ddbc494eb --- /dev/null +++ b/contrib/ffmpeg/A02-hevcmux.patch @@ -0,0 +1,1411 @@ +diff --git a/libavcodec/golomb.h b/libavcodec/golomb.h +index efe5059..ce3500f 100644 +--- a/libavcodec/golomb.h ++++ b/libavcodec/golomb.h +@@ -206,6 +206,18 @@ static inline int get_se_golomb(GetBitContext *gb) + } + } + ++static inline int get_se_golomb_long(GetBitContext *gb) ++{ ++ unsigned int buf = get_ue_golomb_long(gb); ++ ++ if (buf & 1) ++ buf = -(buf >> 1); ++ else ++ buf = (buf >> 1); ++ ++ return buf; ++} ++ + static inline int svq3_get_se_golomb(GetBitContext *gb) + { + unsigned int buf; +diff --git a/libavformat/Makefile b/libavformat/Makefile +index d491d43..5694314 100644 +--- a/libavformat/Makefile ++++ b/libavformat/Makefile +@@ -168,7 +168,7 @@ OBJS-$(CONFIG_M4V_MUXER) += rawenc.o + OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o \ + isom.o rmsipr.o + OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \ +- isom.o avc.o \ ++ isom.o avc.o hevc.o \ + flacenc_header.o avlanguage.o wv.o + OBJS-$(CONFIG_MD5_MUXER) += md5enc.o + OBJS-$(CONFIG_MJPEG_DEMUXER) += rawdec.o +@@ -179,7 +179,7 @@ OBJS-$(CONFIG_MM_DEMUXER) += mm.o + OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o pcm.o + OBJS-$(CONFIG_MMF_MUXER) += mmf.o + OBJS-$(CONFIG_MOV_DEMUXER) += mov.o isom.o mov_chan.o +-OBJS-$(CONFIG_MOV_MUXER) += movenc.o isom.o avc.o \ ++OBJS-$(CONFIG_MOV_MUXER) += movenc.o isom.o avc.o hevc.o \ + movenchint.o mov_chan.o + OBJS-$(CONFIG_MP2_MUXER) += mp3enc.o rawenc.o id3v2enc.o + OBJS-$(CONFIG_MP3_DEMUXER) += mp3dec.o +diff --git a/libavformat/hevc.c b/libavformat/hevc.c +new file mode 100644 +index 0000000..37b35b4 +--- /dev/null ++++ b/libavformat/hevc.c +@@ -0,0 +1,1140 @@ ++/* ++ * Copyright (c) 2014 Tim Walker <[email protected]> ++ * ++ * This file is part of Libav. ++ * ++ * Libav 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. ++ * ++ * Libav 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 Libav; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "libavcodec/get_bits.h" ++#include "libavcodec/golomb.h" ++#include "libavcodec/hevc.h" ++#include "libavutil/intreadwrite.h" ++#include "avc.h" ++#include "avio.h" ++#include "hevc.h" ++ ++#define MAX_SPATIAL_SEGMENTATION 4096 // max. value of u(12) field ++ ++typedef struct HVCCNALUnitArray { ++ uint8_t array_completeness; ++ uint8_t NAL_unit_type; ++ uint16_t numNalus; ++ uint16_t *nalUnitLength; ++ uint8_t **nalUnit; ++} HVCCNALUnitArray; ++ ++typedef struct HEVCDecoderConfigurationRecord { ++ uint8_t configurationVersion; ++ uint8_t general_profile_space; ++ uint8_t general_tier_flag; ++ uint8_t general_profile_idc; ++ uint32_t general_profile_compatibility_flags; ++ uint64_t general_constraint_indicator_flags; ++ uint8_t general_level_idc; ++ uint16_t min_spatial_segmentation_idc; ++ uint8_t parallelismType; ++ uint8_t chromaFormat; ++ uint8_t bitDepthLumaMinus8; ++ uint8_t bitDepthChromaMinus8; ++ uint16_t avgFrameRate; ++ uint8_t constantFrameRate; ++ uint8_t numTemporalLayers; ++ uint8_t temporalIdNested; ++ uint8_t lengthSizeMinusOne; ++ uint8_t numOfArrays; ++ HVCCNALUnitArray *array; ++} HEVCDecoderConfigurationRecord; ++ ++typedef struct HVCCProfileTierLevel { ++ uint8_t profile_space; ++ uint8_t tier_flag; ++ uint8_t profile_idc; ++ uint32_t profile_compatibility_flags; ++ uint64_t constraint_indicator_flags; ++ uint8_t level_idc; ++} HVCCProfileTierLevel; ++ ++static void hvcc_update_ptl(HEVCDecoderConfigurationRecord *hvcc, ++ HVCCProfileTierLevel *ptl) ++{ ++ /* ++ * The value of general_profile_space in all the parameter sets must be ++ * identical. ++ */ ++ hvcc->general_profile_space = ptl->profile_space; ++ ++ /* ++ * The level indication general_level_idc must indicate a level of ++ * capability equal to or greater than the highest level indicated for the ++ * highest tier in all the parameter sets. ++ */ ++ if (hvcc->general_tier_flag < ptl->tier_flag) ++ hvcc->general_level_idc = ptl->level_idc; ++ else ++ hvcc->general_level_idc = FFMAX(hvcc->general_level_idc, ptl->level_idc); ++ ++ /* ++ * The tier indication general_tier_flag must indicate a tier equal to or ++ * greater than the highest tier indicated in all the parameter sets. ++ */ ++ hvcc->general_tier_flag = FFMAX(hvcc->general_tier_flag, ptl->tier_flag); ++ ++ /* ++ * The profile indication general_profile_idc must indicate a profile to ++ * which the stream associated with this configuration record conforms. ++ * ++ * If the sequence parameter sets are marked with different profiles, then ++ * the stream may need examination to determine which profile, if any, the ++ * entire stream conforms to. If the entire stream is not examined, or the ++ * examination reveals that there is no profile to which the entire stream ++ * conforms, then the entire stream must be split into two or more ++ * sub-streams with separate configuration records in which these rules can ++ * be met. ++ * ++ * Note: set the profile to the highest value for the sake of simplicity. ++ */ ++ hvcc->general_profile_idc = FFMAX(hvcc->general_profile_idc, ptl->profile_idc); ++ ++ /* ++ * Each bit in general_profile_compatibility_flags may only be set if all ++ * the parameter sets set that bit. ++ */ ++ hvcc->general_profile_compatibility_flags &= ptl->profile_compatibility_flags; ++ ++ /* ++ * Each bit in general_constraint_indicator_flags may only be set if all ++ * the parameter sets set that bit. ++ */ ++ hvcc->general_constraint_indicator_flags &= ptl->constraint_indicator_flags; ++} ++ ++static void hvcc_parse_ptl(GetBitContext *gb, ++ HEVCDecoderConfigurationRecord *hvcc, ++ unsigned int max_sub_layers_minus1) ++{ ++ unsigned int i; ++ HVCCProfileTierLevel general_ptl; ++ uint8_t sub_layer_profile_present_flag[MAX_SUB_LAYERS]; ++ uint8_t sub_layer_level_present_flag[MAX_SUB_LAYERS]; ++ ++ general_ptl.profile_space = get_bits(gb, 2); ++ general_ptl.tier_flag = get_bits1(gb); ++ general_ptl.profile_idc = get_bits(gb, 5); ++ general_ptl.profile_compatibility_flags = get_bits_long(gb, 32); ++ general_ptl.constraint_indicator_flags = get_bits64(gb, 48); ++ general_ptl.level_idc = get_bits(gb, 8); ++ hvcc_update_ptl(hvcc, &general_ptl); ++ ++ for (i = 0; i < max_sub_layers_minus1; i++) { ++ sub_layer_profile_present_flag[i] = get_bits1(gb); ++ sub_layer_level_present_flag[i] = get_bits1(gb); ++ } ++ ++ if (max_sub_layers_minus1 > 0) ++ for (i = max_sub_layers_minus1; i < 8; i++) ++ skip_bits(gb, 2); // reserved_zero_2bits[i] ++ ++ for (i = 0; i < max_sub_layers_minus1; i++) { ++ if (sub_layer_profile_present_flag[i]) { ++ /* ++ * sub_layer_profile_space[i] u(2) ++ * sub_layer_tier_flag[i] u(1) ++ * sub_layer_profile_idc[i] u(5) ++ * sub_layer_profile_compatibility_flag[i][0..31] u(32) ++ * sub_layer_progressive_source_flag[i] u(1) ++ * sub_layer_interlaced_source_flag[i] u(1) ++ * sub_layer_non_packed_constraint_flag[i] u(1) ++ * sub_layer_frame_only_constraint_flag[i] u(1) ++ * sub_layer_reserved_zero_44bits[i] u(44) ++ */ ++ skip_bits_long(gb, 32); ++ skip_bits_long(gb, 32); ++ skip_bits (gb, 24); ++ } ++ ++ if (sub_layer_level_present_flag[i]) ++ skip_bits(gb, 8); ++ } ++} ++ ++static void skip_sub_layer_hrd_parameters(GetBitContext *gb, ++ unsigned int cpb_cnt_minus1, ++ uint8_t sub_pic_hrd_params_present_flag) ++{ ++ unsigned int i; ++ ++ for (i = 0; i <= cpb_cnt_minus1; i++) { ++ get_ue_golomb_long(gb); // bit_rate_value_minus1 ++ get_ue_golomb_long(gb); // cpb_size_value_minus1 ++ ++ if (sub_pic_hrd_params_present_flag) { ++ get_ue_golomb_long(gb); // cpb_size_du_value_minus1 ++ get_ue_golomb_long(gb); // bit_rate_du_value_minus1 ++ } ++ ++ skip_bits1(gb); // cbr_flag ++ } ++} ++ ++static void skip_hrd_parameters(GetBitContext *gb, uint8_t cprms_present_flag, ++ unsigned int max_sub_layers_minus1) ++{ ++ unsigned int i; ++ uint8_t sub_pic_hrd_params_present_flag = 0; ++ uint8_t nal_hrd_parameters_present_flag = 0; ++ uint8_t vcl_hrd_parameters_present_flag = 0; ++ ++ if (cprms_present_flag) { ++ nal_hrd_parameters_present_flag = get_bits1(gb); ++ vcl_hrd_parameters_present_flag = get_bits1(gb); ++ ++ if (nal_hrd_parameters_present_flag || ++ vcl_hrd_parameters_present_flag) { ++ sub_pic_hrd_params_present_flag = get_bits1(gb); ++ ++ if (sub_pic_hrd_params_present_flag) ++ /* ++ * tick_divisor_minus2 u(8) ++ * du_cpb_removal_delay_increment_length_minus1 u(5) ++ * sub_pic_cpb_params_in_pic_timing_sei_flag u(1) ++ * dpb_output_delay_du_length_minus1 u(5) ++ */ ++ skip_bits(gb, 19); ++ ++ /* ++ * bit_rate_scale u(4) ++ * cpb_size_scale u(4) ++ */ ++ skip_bits(gb, 8); ++ ++ if (sub_pic_hrd_params_present_flag) ++ skip_bits(gb, 4); // cpb_size_du_scale ++ ++ /* ++ * initial_cpb_removal_delay_length_minus1 u(5) ++ * au_cpb_removal_delay_length_minus1 u(5) ++ * dpb_output_delay_length_minus1 u(5) ++ */ ++ skip_bits(gb, 15); ++ } ++ } ++ ++ for (i = 0; i <= max_sub_layers_minus1; i++) { ++ unsigned int cpb_cnt_minus1 = 0; ++ uint8_t low_delay_hrd_flag = 0; ++ uint8_t fixed_pic_rate_within_cvs_flag = 0; ++ uint8_t fixed_pic_rate_general_flag = get_bits1(gb); ++ ++ if (!fixed_pic_rate_general_flag) ++ fixed_pic_rate_within_cvs_flag = get_bits1(gb); ++ ++ if (fixed_pic_rate_within_cvs_flag) ++ get_ue_golomb_long(gb); // elemental_duration_in_tc_minus1 ++ else ++ low_delay_hrd_flag = get_bits1(gb); ++ ++ if (!low_delay_hrd_flag) ++ cpb_cnt_minus1 = get_ue_golomb_long(gb); ++ ++ if (nal_hrd_parameters_present_flag) ++ skip_sub_layer_hrd_parameters(gb, cpb_cnt_minus1, ++ sub_pic_hrd_params_present_flag); ++ ++ if (vcl_hrd_parameters_present_flag) ++ skip_sub_layer_hrd_parameters(gb, cpb_cnt_minus1, ++ sub_pic_hrd_params_present_flag); ++ } ++} ++ ++static void skip_timing_info(GetBitContext *gb) ++{ ++ skip_bits_long(gb, 32); // num_units_in_tick ++ skip_bits_long(gb, 32); // time_scale ++ ++ if (get_bits1(gb)) // poc_proportional_to_timing_flag ++ get_ue_golomb_long(gb); // num_ticks_poc_diff_one_minus1 ++} ++ ++static void hvcc_parse_vui(GetBitContext *gb, ++ HEVCDecoderConfigurationRecord *hvcc, ++ unsigned int max_sub_layers_minus1) ++{ ++ unsigned int min_spatial_segmentation_idc; ++ ++ if (get_bits1(gb)) // aspect_ratio_info_present_flag ++ if (get_bits(gb, 8) == 255) // aspect_ratio_idc ++ skip_bits_long(gb, 32); // sar_width u(16), sar_height u(16) ++ ++ if (get_bits1(gb)) // overscan_info_present_flag ++ skip_bits1(gb); // overscan_appropriate_flag ++ ++ if (get_bits1(gb)) { // video_signal_type_present_flag ++ skip_bits(gb, 4); // video_format u(3), video_full_range_flag u(1) ++ ++ if (get_bits1(gb)) // colour_description_present_flag ++ /* ++ * colour_primaries u(8) ++ * transfer_characteristics u(8) ++ * matrix_coeffs u(8) ++ */ ++ skip_bits(gb, 24); ++ } ++ ++ if (get_bits1(gb)) { // chroma_loc_info_present_flag ++ get_ue_golomb_long(gb); // chroma_sample_loc_type_top_field ++ get_ue_golomb_long(gb); // chroma_sample_loc_type_bottom_field ++ } ++ ++ /* ++ * neutral_chroma_indication_flag u(1) ++ * field_seq_flag u(1) ++ * frame_field_info_present_flag u(1) ++ */ ++ skip_bits(gb, 3); ++ ++ if (get_bits1(gb)) { // default_display_window_flag ++ get_ue_golomb_long(gb); // def_disp_win_left_offset ++ get_ue_golomb_long(gb); // def_disp_win_right_offset ++ get_ue_golomb_long(gb); // def_disp_win_top_offset ++ get_ue_golomb_long(gb); // def_disp_win_bottom_offset ++ } ++ ++ if (get_bits1(gb)) { // vui_timing_info_present_flag ++ skip_timing_info(gb); ++ ++ if (get_bits1(gb)) // vui_hrd_parameters_present_flag ++ skip_hrd_parameters(gb, 1, max_sub_layers_minus1); ++ } ++ ++ if (get_bits1(gb)) { // bitstream_restriction_flag ++ /* ++ * tiles_fixed_structure_flag u(1) ++ * motion_vectors_over_pic_boundaries_flag u(1) ++ * restricted_ref_pic_lists_flag u(1) ++ */ ++ skip_bits(gb, 3); ++ ++ min_spatial_segmentation_idc = get_ue_golomb_long(gb); ++ ++ /* ++ * unsigned int(12) min_spatial_segmentation_idc; ++ * ++ * The min_spatial_segmentation_idc indication must indicate a level of ++ * spatial segmentation equal to or less than the lowest level of ++ * spatial segmentation indicated in all the parameter sets. ++ */ ++ hvcc->min_spatial_segmentation_idc = FFMIN(hvcc->min_spatial_segmentation_idc, ++ min_spatial_segmentation_idc); ++ ++ get_ue_golomb_long(gb); // max_bytes_per_pic_denom ++ get_ue_golomb_long(gb); // max_bits_per_min_cu_denom ++ get_ue_golomb_long(gb); // log2_max_mv_length_horizontal ++ get_ue_golomb_long(gb); // log2_max_mv_length_vertical ++ } ++} ++ ++static void skip_sub_layer_ordering_info(GetBitContext *gb) ++{ ++ get_ue_golomb_long(gb); // max_dec_pic_buffering_minus1 ++ get_ue_golomb_long(gb); // max_num_reorder_pics ++ get_ue_golomb_long(gb); // max_latency_increase_plus1 ++} ++ ++static int hvcc_parse_vps(GetBitContext *gb, ++ HEVCDecoderConfigurationRecord *hvcc) ++{ ++ unsigned int vps_max_sub_layers_minus1; ++ ++ /* ++ * vps_video_parameter_set_id u(4) ++ * vps_reserved_three_2bits u(2) ++ * vps_max_layers_minus1 u(6) ++ */ ++ skip_bits(gb, 12); ++ ++ vps_max_sub_layers_minus1 = get_bits(gb, 3); ++ ++ /* ++ * numTemporalLayers greater than 1 indicates that the stream to which this ++ * configuration record applies is temporally scalable and the contained ++ * number of temporal layers (also referred to as temporal sub-layer or ++ * sub-layer in ISO/IEC 23008-2) is equal to numTemporalLayers. Value 1 ++ * indicates that the stream is not temporally scalable. Value 0 indicates ++ * that it is unknown whether the stream is temporally scalable. ++ */ ++ hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers, ++ vps_max_sub_layers_minus1 + 1); ++ ++ /* ++ * vps_temporal_id_nesting_flag u(1) ++ * vps_reserved_0xffff_16bits u(16) ++ */ ++ skip_bits(gb, 17); ++ ++ hvcc_parse_ptl(gb, hvcc, vps_max_sub_layers_minus1); ++ ++ /* nothing useful for hvcC past this point */ ++ return 0; ++} ++ ++static void skip_scaling_list_data(GetBitContext *gb) ++{ ++ int i, j, k, num_coeffs; ++ ++ for (i = 0; i < 4; i++) ++ for (j = 0; j < (i == 3 ? 2 : 6); j++) ++ if (!get_bits1(gb)) // scaling_list_pred_mode_flag[i][j] ++ get_ue_golomb_long(gb); // scaling_list_pred_matrix_id_delta[i][j] ++ else { ++ num_coeffs = FFMIN(64, 1 << (4 + (i << 1))); ++ ++ if (i > 1) ++ get_se_golomb_long(gb); // scaling_list_dc_coef_minus8[i-2][j] ++ ++ for (k = 0; k < num_coeffs; k++) ++ get_se_golomb_long(gb); // scaling_list_delta_coef ++ } ++} ++ ++static int parse_rps(GetBitContext *gb, unsigned int rps_idx, ++ unsigned int num_rps, ++ unsigned int num_delta_pocs[MAX_SHORT_TERM_RPS_COUNT]) ++{ ++ unsigned int i; ++ ++ if (rps_idx && get_bits1(gb)) { // inter_ref_pic_set_prediction_flag ++ /* this should only happen for slice headers, and this isn't one */ ++ if (rps_idx >= num_rps) ++ return AVERROR_INVALIDDATA; ++ ++ skip_bits1 (gb); // delta_rps_sign ++ get_ue_golomb_long(gb); // abs_delta_rps_minus1 ++ ++ num_delta_pocs[rps_idx] = 0; ++ ++ /* ++ * From libavcodec/hevc_ps.c: ++ * ++ * if (is_slice_header) { ++ * //foo ++ * } else ++ * rps_ridx = &sps->st_rps[rps - sps->st_rps - 1]; ++ * ++ * where: ++ * rps: &sps->st_rps[rps_idx] ++ * sps->st_rps: &sps->st_rps[0] ++ * is_slice_header: rps_idx == num_rps ++ * ++ * thus: ++ * if (num_rps != rps_idx) ++ * rps_ridx = &sps->st_rps[rps_idx - 1]; ++ * ++ * NumDeltaPocs[RefRpsIdx]: num_delta_pocs[rps_idx - 1] ++ */ ++ for (i = 0; i < num_delta_pocs[rps_idx - 1]; i++) { ++ uint8_t use_delta_flag = 0; ++ uint8_t used_by_curr_pic_flag = get_bits1(gb); ++ if (!used_by_curr_pic_flag) ++ use_delta_flag = get_bits1(gb); ++ ++ if (used_by_curr_pic_flag || use_delta_flag) ++ num_delta_pocs[rps_idx]++; ++ } ++ } else { ++ unsigned int num_negative_pics = get_ue_golomb_long(gb); ++ unsigned int num_positive_pics = get_ue_golomb_long(gb); ++ ++ num_delta_pocs[rps_idx] = num_negative_pics + num_positive_pics; ++ ++ for (i = 0; i < num_negative_pics; i++) { ++ get_ue_golomb_long(gb); // delta_poc_s0_minus1[rps_idx] ++ skip_bits1 (gb); // used_by_curr_pic_s0_flag[rps_idx] ++ } ++ ++ for (i = 0; i < num_positive_pics; i++) { ++ get_ue_golomb_long(gb); // delta_poc_s1_minus1[rps_idx] ++ skip_bits1 (gb); // used_by_curr_pic_s1_flag[rps_idx] ++ } ++ } ++ ++ return 0; ++} ++ ++static int hvcc_parse_sps(GetBitContext *gb, ++ HEVCDecoderConfigurationRecord *hvcc) ++{ ++ unsigned int i, sps_max_sub_layers_minus1, log2_max_pic_order_cnt_lsb_minus4; ++ unsigned int num_short_term_ref_pic_sets, num_delta_pocs[MAX_SHORT_TERM_RPS_COUNT]; ++ ++ skip_bits(gb, 4); // sps_video_parameter_set_id ++ ++ sps_max_sub_layers_minus1 = get_bits (gb, 3); ++ ++ /* ++ * numTemporalLayers greater than 1 indicates that the stream to which this ++ * configuration record applies is temporally scalable and the contained ++ * number of temporal layers (also referred to as temporal sub-layer or ++ * sub-layer in ISO/IEC 23008-2) is equal to numTemporalLayers. Value 1 ++ * indicates that the stream is not temporally scalable. Value 0 indicates ++ * that it is unknown whether the stream is temporally scalable. ++ */ ++ hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers, ++ sps_max_sub_layers_minus1 + 1); ++ ++ hvcc->temporalIdNested = get_bits1(gb); ++ ++ hvcc_parse_ptl(gb, hvcc, sps_max_sub_layers_minus1); ++ ++ get_ue_golomb_long(gb); // sps_seq_parameter_set_id ++ ++ hvcc->chromaFormat = get_ue_golomb_long(gb); ++ ++ if (hvcc->chromaFormat == 3) ++ skip_bits1(gb); // separate_colour_plane_flag ++ ++ get_ue_golomb_long(gb); // pic_width_in_luma_samples ++ get_ue_golomb_long(gb); // pic_height_in_luma_samples ++ ++ if (get_bits1(gb)) { // conformance_window_flag ++ get_ue_golomb_long(gb); // conf_win_left_offset ++ get_ue_golomb_long(gb); // conf_win_right_offset ++ get_ue_golomb_long(gb); // conf_win_top_offset ++ get_ue_golomb_long(gb); // conf_win_bottom_offset ++ } ++ ++ hvcc->bitDepthLumaMinus8 = get_ue_golomb_long(gb); ++ hvcc->bitDepthChromaMinus8 = get_ue_golomb_long(gb); ++ log2_max_pic_order_cnt_lsb_minus4 = get_ue_golomb_long(gb); ++ ++ /* sps_sub_layer_ordering_info_present_flag */ ++ i = get_bits1(gb) ? 0 : sps_max_sub_layers_minus1; ++ for (; i <= sps_max_sub_layers_minus1; i++) ++ skip_sub_layer_ordering_info(gb); ++ ++ get_ue_golomb_long(gb); // log2_min_luma_coding_block_size_minus3 ++ get_ue_golomb_long(gb); // log2_diff_max_min_luma_coding_block_size ++ get_ue_golomb_long(gb); // log2_min_transform_block_size_minus2 ++ get_ue_golomb_long(gb); // log2_diff_max_min_transform_block_size ++ get_ue_golomb_long(gb); // max_transform_hierarchy_depth_inter ++ get_ue_golomb_long(gb); // max_transform_hierarchy_depth_intra ++ ++ if (get_bits1(gb) && // scaling_list_enabled_flag ++ get_bits1(gb)) // sps_scaling_list_data_present_flag ++ skip_scaling_list_data(gb); ++ ++ skip_bits1(gb); // amp_enabled_flag ++ skip_bits1(gb); // sample_adaptive_offset_enabled_flag ++ ++ if (get_bits1(gb)) { // pcm_enabled_flag ++ skip_bits (gb, 4); // pcm_sample_bit_depth_luma_minus1 ++ skip_bits (gb, 4); // pcm_sample_bit_depth_chroma_minus1 ++ get_ue_golomb_long(gb); // log2_min_pcm_luma_coding_block_size_minus3 ++ get_ue_golomb_long(gb); // log2_diff_max_min_pcm_luma_coding_block_size ++ skip_bits1 (gb); // pcm_loop_filter_disabled_flag ++ } ++ ++ num_short_term_ref_pic_sets = get_ue_golomb_long(gb); ++ if (num_short_term_ref_pic_sets > MAX_SHORT_TERM_RPS_COUNT) ++ return AVERROR_INVALIDDATA; ++ ++ for (i = 0; i < num_short_term_ref_pic_sets; i++) { ++ int ret = parse_rps(gb, i, num_short_term_ref_pic_sets, num_delta_pocs); ++ if (ret < 0) ++ return ret; ++ } ++ ++ if (get_bits1(gb)) { // long_term_ref_pics_present_flag ++ for (i = 0; i < get_ue_golomb_long(gb); i++) { // num_long_term_ref_pics_sps ++ int len = FFMIN(log2_max_pic_order_cnt_lsb_minus4 + 4, 16); ++ skip_bits (gb, len); // lt_ref_pic_poc_lsb_sps[i] ++ skip_bits1(gb); // used_by_curr_pic_lt_sps_flag[i] ++ } ++ } ++ ++ skip_bits1(gb); // sps_temporal_mvp_enabled_flag ++ skip_bits1(gb); // strong_intra_smoothing_enabled_flag ++ ++ if (get_bits1(gb)) // vui_parameters_present_flag ++ hvcc_parse_vui(gb, hvcc, sps_max_sub_layers_minus1); ++ ++ /* nothing useful for hvcC past this point */ ++ return 0; ++} ++ ++static int hvcc_parse_pps(GetBitContext *gb, ++ HEVCDecoderConfigurationRecord *hvcc) ++{ ++ uint8_t tiles_enabled_flag, entropy_coding_sync_enabled_flag; ++ ++ get_ue_golomb_long(gb); // pps_pic_parameter_set_id ++ get_ue_golomb_long(gb); // pps_seq_parameter_set_id ++ ++ /* ++ * dependent_slice_segments_enabled_flag u(1) ++ * output_flag_present_flag u(1) ++ * num_extra_slice_header_bits u(3) ++ * sign_data_hiding_enabled_flag u(1) ++ * cabac_init_present_flag u(1) ++ */ ++ skip_bits(gb, 7); ++ ++ get_ue_golomb_long(gb); // num_ref_idx_l0_default_active_minus1 ++ get_ue_golomb_long(gb); // num_ref_idx_l1_default_active_minus1 ++ get_se_golomb_long(gb); // init_qp_minus26 ++ ++ /* ++ * constrained_intra_pred_flag u(1) ++ * transform_skip_enabled_flag u(1) ++ */ ++ skip_bits(gb, 2); ++ ++ if (get_bits1(gb)) // cu_qp_delta_enabled_flag ++ get_ue_golomb_long(gb); // diff_cu_qp_delta_depth ++ ++ get_se_golomb_long(gb); // pps_cb_qp_offset ++ get_se_golomb_long(gb); // pps_cr_qp_offset ++ ++ /* ++ * weighted_pred_flag u(1) ++ * weighted_bipred_flag u(1) ++ * transquant_bypass_enabled_flag u(1) ++ */ ++ skip_bits(gb, 3); ++ ++ tiles_enabled_flag = get_bits1(gb); ++ entropy_coding_sync_enabled_flag = get_bits1(gb); ++ ++ if (entropy_coding_sync_enabled_flag && tiles_enabled_flag) ++ hvcc->parallelismType = 0; // mixed-type parallel decoding ++ else if (entropy_coding_sync_enabled_flag) ++ hvcc->parallelismType = 3; // wavefront-based parallel decoding ++ else if (tiles_enabled_flag) ++ hvcc->parallelismType = 2; // tile-based parallel decoding ++ else ++ hvcc->parallelismType = 1; // slice-based parallel decoding ++ ++ /* nothing useful for hvcC past this point */ ++ return 0; ++} ++ ++static uint8_t *nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, ++ uint32_t *dst_len) ++{ ++ uint8_t *dst; ++ uint32_t i, len; ++ ++ dst = av_malloc(src_len); ++ if (!dst) ++ return NULL; ++ ++ /* NAL unit header (2 bytes) */ ++ i = len = 0; ++ while (i < 2 && i < src_len) ++ dst[len++] = src[i++]; ++ ++ while (i + 2 < src_len) ++ if (!src[i] && !src[i + 1] && src[i + 2] == 3) { ++ dst[len++] = src[i++]; ++ dst[len++] = src[i++]; ++ i++; // remove emulation_prevention_three_byte ++ } else ++ dst[len++] = src[i++]; ++ ++ while (i < src_len) ++ dst[len++] = src[i++]; ++ ++ *dst_len = len; ++ return dst; ++} ++ ++ ++ ++static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type) ++{ ++ skip_bits1(gb); // forbidden_zero_bit ++ ++ *nal_type = get_bits(gb, 6); ++ ++ /* ++ * nuh_layer_id u(6) ++ * nuh_temporal_id_plus1 u(3) ++ */ ++ skip_bits(gb, 9); ++} ++ ++static int hvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, ++ uint8_t nal_type, int ps_array_completeness, ++ HEVCDecoderConfigurationRecord *hvcc) ++{ ++ int ret; ++ uint8_t index; ++ uint16_t numNalus; ++ HVCCNALUnitArray *array; ++ ++ for (index = 0; index < hvcc->numOfArrays; index++) ++ if (hvcc->array[index].NAL_unit_type == nal_type) ++ break; ++ ++ if (index >= hvcc->numOfArrays) { ++ uint8_t i; ++ ++ ret = av_reallocp_array(&hvcc->array, index + 1, sizeof(HVCCNALUnitArray)); ++ if (ret < 0) ++ return ret; ++ ++ for (i = hvcc->numOfArrays; i <= index; i++) ++ memset(&hvcc->array[i], 0, sizeof(HVCCNALUnitArray)); ++ hvcc->numOfArrays = index + 1; ++ } ++ ++ array = &hvcc->array[index]; ++ numNalus = array->numNalus; ++ ++ ret = av_reallocp_array(&array->nalUnit, numNalus + 1, sizeof(uint8_t*)); ++ if (ret < 0) ++ return ret; ++ ++ ret = av_reallocp_array(&array->nalUnitLength, numNalus + 1, sizeof(uint16_t)); ++ if (ret < 0) ++ return ret; ++ ++ array->nalUnit [numNalus] = nal_buf; ++ array->nalUnitLength[numNalus] = nal_size; ++ array->NAL_unit_type = nal_type; ++ array->numNalus++; ++ ++ /* ++ * When the sample entry name is ‘hvc1’, the default and mandatory value of ++ * array_completeness is 1 for arrays of all types of parameter sets, and 0 ++ * for all other arrays. When the sample entry name is ‘hev1’, the default ++ * value of array_completeness is 0 for all arrays. ++ */ ++ if (nal_type == NAL_VPS || nal_type == NAL_SPS || nal_type == NAL_PPS) ++ array->array_completeness = ps_array_completeness; ++ ++ return 0; ++} ++ ++static int hvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, ++ int ps_array_completeness, ++ HEVCDecoderConfigurationRecord *hvcc) ++{ ++ int ret = 0; ++ GetBitContext gbc; ++ uint8_t nal_type; ++ uint8_t *rbsp_buf; ++ uint32_t rbsp_size; ++ ++ rbsp_buf = nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size); ++ if (!rbsp_buf) { ++ ret = AVERROR(ENOMEM); ++ goto end; ++ } ++ ++ ret = init_get_bits8(&gbc, rbsp_buf, rbsp_size); ++ if (ret < 0) ++ goto end; ++ ++ nal_unit_parse_header(&gbc, &nal_type); ++ ++ /* ++ * Note: only 'declarative' SEI messages are allowed in ++ * hvcC. Perhaps the SEI playload type should be checked ++ * and non-declarative SEI messages discarded? ++ */ ++ switch (nal_type) { ++ case NAL_VPS: ++ case NAL_SPS: ++ case NAL_PPS: ++ case NAL_SEI_PREFIX: ++ case NAL_SEI_SUFFIX: ++ ret = hvcc_array_add_nal_unit(nal_buf, nal_size, nal_type, ++ ps_array_completeness, hvcc); ++ if (ret < 0) ++ goto end; ++ else if (nal_type == NAL_VPS) ++ ret = hvcc_parse_vps(&gbc, hvcc); ++ else if (nal_type == NAL_SPS) ++ ret = hvcc_parse_sps(&gbc, hvcc); ++ else if (nal_type == NAL_PPS) ++ ret = hvcc_parse_pps(&gbc, hvcc); ++ if (ret < 0) ++ goto end; ++ break; ++ default: ++ ret = AVERROR_INVALIDDATA; ++ goto end; ++ } ++ ++end: ++ av_free(rbsp_buf); ++ return ret; ++} ++ ++static void hvcc_init(HEVCDecoderConfigurationRecord *hvcc) ++{ ++ memset(hvcc, 0, sizeof(HEVCDecoderConfigurationRecord)); ++ hvcc->configurationVersion = 1; ++ hvcc->lengthSizeMinusOne = 3; // 4 bytes ++ ++ /* ++ * The following fields have all their valid bits set by default, ++ * the ProfileTierLevel parsing code will unset them when needed. ++ */ ++ hvcc->general_profile_compatibility_flags = 0xffffffff; ++ hvcc->general_constraint_indicator_flags = 0xffffffffffff; ++ ++ /* ++ * Initialize this field with an invalid value which can be used to detect ++ * whether we didn't see any VUI (in wich case it should be reset to zero). ++ */ ++ hvcc->min_spatial_segmentation_idc = MAX_SPATIAL_SEGMENTATION + 1; ++} ++ ++static void hvcc_close(HEVCDecoderConfigurationRecord *hvcc) ++{ ++ uint8_t i; ++ ++ for (i = 0; i < hvcc->numOfArrays; i++) { ++ hvcc->array[i].numNalus = 0; ++ av_freep(&hvcc->array[i].nalUnit); ++ av_freep(&hvcc->array[i].nalUnitLength); ++ } ++ ++ hvcc->numOfArrays = 0; ++ av_freep(&hvcc->array); ++} ++ ++static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) ++{ ++ uint8_t i; ++ uint16_t j, vps_count = 0, sps_count = 0, pps_count = 0; ++ ++ /* ++ * We only support writing HEVCDecoderConfigurationRecord version 1. ++ */ ++ hvcc->configurationVersion = 1; ++ ++ /* ++ * If min_spatial_segmentation_idc is invalid, reset to 0 (unspecified). ++ */ ++ if (hvcc->min_spatial_segmentation_idc > MAX_SPATIAL_SEGMENTATION) ++ hvcc->min_spatial_segmentation_idc = 0; ++ ++ /* ++ * parallelismType indicates the type of parallelism that is used to meet ++ * the restrictions imposed by min_spatial_segmentation_idc when the value ++ * of min_spatial_segmentation_idc is greater than 0. ++ */ ++ if (!hvcc->min_spatial_segmentation_idc) ++ hvcc->parallelismType = 0; ++ ++ /* ++ * It's unclear how to properly compute these fields, so ++ * let's always set them to values meaning 'unspecified'. ++ */ ++ hvcc->avgFrameRate = 0; ++ hvcc->constantFrameRate = 0; ++ ++ av_dlog(NULL, "configurationVersion: %"PRIu8"\n", ++ hvcc->configurationVersion); ++ av_dlog(NULL, "general_profile_space: %"PRIu8"\n", ++ hvcc->general_profile_space); ++ av_dlog(NULL, "general_tier_flag: %"PRIu8"\n", ++ hvcc->general_tier_flag); ++ av_dlog(NULL, "general_profile_idc: %"PRIu8"\n", ++ hvcc->general_profile_idc); ++ av_dlog(NULL, "general_profile_compatibility_flags: 0x%08"PRIx32"\n", ++ hvcc->general_profile_compatibility_flags); ++ av_dlog(NULL, "general_constraint_indicator_flags: 0x%012"PRIx64"\n", ++ hvcc->general_constraint_indicator_flags); ++ av_dlog(NULL, "general_level_idc: %"PRIu8"\n", ++ hvcc->general_level_idc); ++ av_dlog(NULL, "min_spatial_segmentation_idc: %"PRIu16"\n", ++ hvcc->min_spatial_segmentation_idc); ++ av_dlog(NULL, "parallelismType: %"PRIu8"\n", ++ hvcc->parallelismType); ++ av_dlog(NULL, "chromaFormat: %"PRIu8"\n", ++ hvcc->chromaFormat); ++ av_dlog(NULL, "bitDepthLumaMinus8: %"PRIu8"\n", ++ hvcc->bitDepthLumaMinus8); ++ av_dlog(NULL, "bitDepthChromaMinus8: %"PRIu8"\n", ++ hvcc->bitDepthChromaMinus8); ++ av_dlog(NULL, "avgFrameRate: %"PRIu16"\n", ++ hvcc->avgFrameRate); ++ av_dlog(NULL, "constantFrameRate: %"PRIu8"\n", ++ hvcc->constantFrameRate); ++ av_dlog(NULL, "numTemporalLayers: %"PRIu8"\n", ++ hvcc->numTemporalLayers); ++ av_dlog(NULL, "temporalIdNested: %"PRIu8"\n", ++ hvcc->temporalIdNested); ++ av_dlog(NULL, "lengthSizeMinusOne: %"PRIu8"\n", ++ hvcc->lengthSizeMinusOne); ++ av_dlog(NULL, "numOfArrays: %"PRIu8"\n", ++ hvcc->numOfArrays); ++ for (i = 0; i < hvcc->numOfArrays; i++) { ++ av_dlog(NULL, "array_completeness[%"PRIu8"]: %"PRIu8"\n", ++ i, hvcc->array[i].array_completeness); ++ av_dlog(NULL, "NAL_unit_type[%"PRIu8"]: %"PRIu8"\n", ++ i, hvcc->array[i].NAL_unit_type); ++ av_dlog(NULL, "numNalus[%"PRIu8"]: %"PRIu16"\n", ++ i, hvcc->array[i].numNalus); ++ for (j = 0; j < hvcc->array[i].numNalus; j++) ++ av_dlog(NULL, ++ "nalUnitLength[%"PRIu8"][%"PRIu16"]: %"PRIu16"\n", ++ i, j, hvcc->array[i].nalUnitLength[j]); ++ } ++ ++ /* ++ * We need at least one of each: VPS, SPS and PPS. ++ */ ++ for (i = 0; i < hvcc->numOfArrays; i++) ++ switch (hvcc->array[i].NAL_unit_type) { ++ case NAL_VPS: ++ vps_count += hvcc->array[i].numNalus; ++ break; ++ case NAL_SPS: ++ sps_count += hvcc->array[i].numNalus; ++ break; ++ case NAL_PPS: ++ pps_count += hvcc->array[i].numNalus; ++ break; ++ default: ++ break; ++ } ++ if (!vps_count || vps_count > MAX_VPS_COUNT || ++ !sps_count || sps_count > MAX_SPS_COUNT || ++ !pps_count || pps_count > MAX_PPS_COUNT) ++ return AVERROR_INVALIDDATA; ++ ++ /* unsigned int(8) configurationVersion = 1; */ ++ avio_w8(pb, hvcc->configurationVersion); ++ ++ /* ++ * unsigned int(2) general_profile_space; ++ * unsigned int(1) general_tier_flag; ++ * unsigned int(5) general_profile_idc; ++ */ ++ avio_w8(pb, hvcc->general_profile_space << 6 | ++ hvcc->general_tier_flag << 5 | ++ hvcc->general_profile_idc); ++ ++ /* unsigned int(32) general_profile_compatibility_flags; */ ++ avio_wb32(pb, hvcc->general_profile_compatibility_flags); ++ ++ /* unsigned int(48) general_constraint_indicator_flags; */ ++ avio_wb32(pb, hvcc->general_constraint_indicator_flags >> 16); ++ avio_wb16(pb, hvcc->general_constraint_indicator_flags); ++ ++ /* unsigned int(8) general_level_idc; */ ++ avio_w8(pb, hvcc->general_level_idc); ++ ++ /* ++ * bit(4) reserved = ‘1111’b; ++ * unsigned int(12) min_spatial_segmentation_idc; ++ */ ++ avio_wb16(pb, hvcc->min_spatial_segmentation_idc | 0xf000); ++ ++ /* ++ * bit(6) reserved = ‘111111’b; ++ * unsigned int(2) parallelismType; ++ */ ++ avio_w8(pb, hvcc->parallelismType | 0xfc); ++ ++ /* ++ * bit(6) reserved = ‘111111’b; ++ * unsigned int(2) chromaFormat; ++ */ ++ avio_w8(pb, hvcc->chromaFormat | 0xfc); ++ ++ /* ++ * bit(5) reserved = ‘11111’b; ++ * unsigned int(3) bitDepthLumaMinus8; ++ */ ++ avio_w8(pb, hvcc->bitDepthLumaMinus8 | 0xf8); ++ ++ /* ++ * bit(5) reserved = ‘11111’b; ++ * unsigned int(3) bitDepthChromaMinus8; ++ */ ++ avio_w8(pb, hvcc->bitDepthChromaMinus8 | 0xf8); ++ ++ /* bit(16) avgFrameRate; */ ++ avio_wb16(pb, hvcc->avgFrameRate); ++ ++ /* ++ * bit(2) constantFrameRate; ++ * bit(3) numTemporalLayers; ++ * bit(1) temporalIdNested; ++ * unsigned int(2) lengthSizeMinusOne; ++ */ ++ avio_w8(pb, hvcc->constantFrameRate << 6 | ++ hvcc->numTemporalLayers << 3 | ++ hvcc->temporalIdNested << 2 | ++ hvcc->lengthSizeMinusOne); ++ ++ /* unsigned int(8) numOfArrays; */ ++ avio_w8(pb, hvcc->numOfArrays); ++ ++ for (i = 0; i < hvcc->numOfArrays; i++) { ++ /* ++ * bit(1) array_completeness; ++ * unsigned int(1) reserved = 0; ++ * unsigned int(6) NAL_unit_type; ++ */ ++ avio_w8(pb, hvcc->array[i].array_completeness << 7 | ++ hvcc->array[i].NAL_unit_type & 0x3f); ++ ++ /* unsigned int(16) numNalus; */ ++ avio_wb16(pb, hvcc->array[i].numNalus); ++ ++ for (j = 0; j < hvcc->array[i].numNalus; j++) { ++ /* unsigned int(16) nalUnitLength; */ ++ avio_wb16(pb, hvcc->array[i].nalUnitLength[j]); ++ ++ /* bit(8*nalUnitLength) nalUnit; */ ++ avio_write(pb, hvcc->array[i].nalUnit[j], ++ hvcc->array[i].nalUnitLength[j]); ++ } ++ } ++ ++ return 0; ++} ++ ++int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in, ++ int size, int filter_ps, int *ps_count) ++{ ++ int num_ps = 0, ret = 0; ++ uint8_t *buf, *end, *start = NULL; ++ ++ if (!filter_ps) { ++ ret = ff_avc_parse_nal_units(pb, buf_in, size); ++ goto end; ++ } ++ ++ ret = ff_avc_parse_nal_units_buf(buf_in, &start, &size); ++ if (ret < 0) ++ goto end; ++ ++ ret = 0; ++ buf = start; ++ end = start + size; ++ ++ while (end - buf > 4) { ++ uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4); ++ uint8_t type = (buf[4] >> 1) & 0x3f; ++ ++ buf += 4; ++ ++ switch (type) { ++ case NAL_VPS: ++ case NAL_SPS: ++ case NAL_PPS: ++ num_ps++; ++ break; ++ default: ++ ret += 4 + len; ++ avio_wb32(pb, len); ++ avio_write(pb, buf, len); ++ break; ++ } ++ ++ buf += len; ++ } ++ ++end: ++ av_free(start); ++ if (ps_count) ++ *ps_count = num_ps; ++ return ret; ++} ++ ++int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, ++ int *size, int filter_ps, int *ps_count) ++{ ++ AVIOContext *pb; ++ int ret; ++ ++ ret = avio_open_dyn_buf(&pb); ++ if (ret < 0) ++ return ret; ++ ++ ret = ff_hevc_annexb2mp4(pb, buf_in, *size, filter_ps, ps_count); ++ *size = avio_close_dyn_buf(pb, buf_out); ++ ++ return ret; ++} ++ ++int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, ++ int size, int ps_array_completeness) ++{ ++ int ret = 0; ++ uint8_t *buf, *end, *start = NULL; ++ HEVCDecoderConfigurationRecord hvcc; ++ ++ hvcc_init(&hvcc); ++ ++ if (size < 6) { ++ /* We can't write a valid hvcC from the provided data */ ++ ret = AVERROR_INVALIDDATA; ++ goto end; ++ } else if (*data == 1) { ++ /* Data is already hvcC-formatted */ ++ avio_write(pb, data, size); ++ goto end; ++ } else if (!(AV_RB24(data) == 1 || AV_RB32(data) == 1)) { ++ /* Not a valid Annex B start code prefix */ ++ ret = AVERROR_INVALIDDATA; ++ goto end; ++ } ++ ++ ret = ff_avc_parse_nal_units_buf(data, &start, &size); ++ if (ret < 0) ++ goto end; ++ ++ buf = start; ++ end = start + size; ++ ++ while (end - buf > 4) { ++ uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4); ++ uint8_t type = (buf[4] >> 1) & 0x3f; ++ ++ buf += 4; ++ ++ switch (type) { ++ case NAL_VPS: ++ case NAL_SPS: ++ case NAL_PPS: ++ case NAL_SEI_PREFIX: ++ case NAL_SEI_SUFFIX: ++ ret = hvcc_add_nal_unit(buf, len, ps_array_completeness, &hvcc); ++ if (ret < 0) ++ goto end; ++ break; ++ default: ++ break; ++ } ++ ++ buf += len; ++ } ++ ++ ret = hvcc_write(pb, &hvcc); ++ ++end: ++ hvcc_close(&hvcc); ++ av_free(start); ++ return ret; ++} +diff --git a/libavformat/hevc.h b/libavformat/hevc.h +new file mode 100644 +index 0000000..03c43bd +--- /dev/null ++++ b/libavformat/hevc.h +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (c) 2014 Tim Walker <[email protected]> ++ * ++ * This file is part of Libav. ++ * ++ * Libav 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. ++ * ++ * Libav 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 Libav; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/** ++ * @file ++ * internal header for HEVC (de)muxer utilities ++ */ ++ ++#ifndef AVFORMAT_HEVC_H ++#define AVFORMAT_HEVC_H ++ ++#include <stdint.h> ++#include "avio.h" ++ ++/** ++ * Writes Annex B formatted HEVC NAL units to the provided AVIOContext. ++ * ++ * The NAL units are converted to an MP4-compatible format (start code prefixes ++ * are replaced by 4-byte size fields, as per ISO/IEC 14496-15). ++ * ++ * If filter_ps is non-zero, any HEVC parameter sets found in the input will be ++ * discarded, and *ps_count will be set to the number of discarded PS NAL units. ++ * ++ * @param pb address of the AVIOContext where the data shall be written ++ * @param buf_in address of the buffer holding the input data ++ * @param size size (in bytes) of the input buffer ++ * @param filter_ps whether to write parameter set NAL units to the output (0) ++ * or to discard them (non-zero) ++ * @param ps_count address of the variable where the number of discarded ++ * parameter set NAL units shall be written, may be NULL ++ * @return the amount (in bytes) of data written in case of success, a negative ++ * value corresponding to an AVERROR code in case of failure ++ */ ++int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in, ++ int size, int filter_ps, int *ps_count); ++ ++/** ++ * Writes Annex B formatted HEVC NAL units to a data buffer. ++ * ++ * The NAL units are converted to an MP4-compatible format (start code prefixes ++ * are replaced by 4-byte size fields, as per ISO/IEC 14496-15). ++ * ++ * If filter_ps is non-zero, any HEVC parameter sets found in the input will be ++ * discarded, and *ps_count will be set to the number of discarded PS NAL units. ++ * ++ * On output, *size holds the size (in bytes) of the output data buffer. ++ * ++ * @param buf_in address of the buffer holding the input data ++ * @param size address of the variable holding the size (in bytes) of the input ++ * buffer (on input) and of the output buffer (on output) ++ * @param buf_out address of the variable holding the address of the output ++ * buffer ++ * @param filter_ps whether to write parameter set NAL units to the output (0) ++ * or to discard them (non-zero) ++ * @param ps_count address of the variable where the number of discarded ++ * parameter set NAL units shall be written, may be NULL ++ * @return the amount (in bytes) of data written in case of success, a negative ++ * value corresponding to an AVERROR code in case of failure ++ */ ++int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, ++ int *size, int filter_ps, int *ps_count); ++ ++/** ++ * Writes HEVC extradata (parameter sets, declarative SEI NAL units) to the ++ * provided AVIOContext. ++ * ++ * If the extradata is Annex B format, it gets converted to hvcC format before ++ * writing. ++ * ++ * @param pb address of the AVIOContext where the hvcC shall be written ++ * @param data address of the buffer holding the data needed to write the hvcC ++ * @param size size (in bytes) of the data buffer ++ * @param ps_array_completeness whether all parameter sets are in the hvcC (1) ++ * or there may be additional parameter sets in the bitstream (0) ++ * @return 0 in case of success, a negative value corresponding to an AVERROR ++ * code in case of failure ++ */ ++int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, ++ int size, int ps_array_completeness); ++ ++#endif /* AVFORMAT_HEVC_H */ +diff --git a/libavformat/isom.c b/libavformat/isom.c +index 9b32b7d..76c455b 100644 +--- a/libavformat/isom.c ++++ b/libavformat/isom.c +@@ -33,6 +33,7 @@ const AVCodecTag ff_mp4_obj_type[] = { + { AV_CODEC_ID_MOV_TEXT , 0x08 }, + { AV_CODEC_ID_MPEG4 , 0x20 }, + { AV_CODEC_ID_H264 , 0x21 }, ++ { AV_CODEC_ID_HEVC , 0x23 }, + { AV_CODEC_ID_AAC , 0x40 }, + { AV_CODEC_ID_MP4ALS , 0x40 }, /* 14496-3 ALS */ + { AV_CODEC_ID_MPEG2VIDEO , 0x61 }, /* MPEG2 Main */ +@@ -136,8 +137,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = { + + { AV_CODEC_ID_RAWVIDEO, MKTAG('W', 'R', 'A', 'W') }, + +- { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, /* HEVC/H.265 which indicates parameter sets shall not be in ES */ + { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') }, /* HEVC/H.265 which indicates parameter sets may be in ES */ ++ { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, /* HEVC/H.265 which indicates parameter sets shall not be in ES */ + + { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, /* AVC-1/H.264 */ + { AV_CODEC_ID_H264, MKTAG('a', 'i', '5', 'p') }, /* AVC-Intra 50M 720p24/30/60 */ +diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c +index cc645a5..08f5552 100644 +--- a/libavformat/matroskaenc.c ++++ b/libavformat/matroskaenc.c +@@ -22,6 +22,7 @@ + #include <stdint.h> + + #include "avc.h" ++#include "hevc.h" + #include "avformat.h" + #include "avlanguage.h" + #include "flacenc.h" +@@ -500,6 +501,8 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo + ret = put_wv_codecpriv(dyn_cp, codec); + else if (codec->codec_id == AV_CODEC_ID_H264) + ret = ff_isom_write_avcc(dyn_cp, codec->extradata, codec->extradata_size); ++ else if (codec->codec_id == AV_CODEC_ID_HEVC) ++ ret = ff_isom_write_hvcc(dyn_cp, codec->extradata, codec->extradata_size, 0); + else if (codec->codec_id == AV_CODEC_ID_ALAC) { + if (codec->extradata_size < 36) { + av_log(s, AV_LOG_ERROR, +@@ -1160,6 +1163,10 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, + if (codec->codec_id == AV_CODEC_ID_H264 && codec->extradata_size > 0 && + (AV_RB24(codec->extradata) == 1 || AV_RB32(codec->extradata) == 1)) + ff_avc_parse_nal_units_buf(pkt->data, &data, &size); ++ else if (codec->codec_id == AV_CODEC_ID_HEVC && codec->extradata_size > 6 && ++ (AV_RB24(codec->extradata) == 1 || AV_RB32(codec->extradata) == 1)) ++ /* extradata is Annex B, assume the bitstream is too and convert it */ ++ ff_hevc_annexb2mp4_buf(pkt->data, &data, &size, 0, NULL); + else if (codec->codec_id == AV_CODEC_ID_WAVPACK) { + int ret = mkv_strip_wavpack(pkt->data, &data, &size); + if (ret < 0) { +diff --git a/libavformat/movenc.c b/libavformat/movenc.c +index 43a1647..415d808 100644 +--- a/libavformat/movenc.c ++++ b/libavformat/movenc.c +@@ -39,6 +39,7 @@ + #include "libavutil/mathematics.h" + #include "libavutil/opt.h" + #include "libavutil/dict.h" ++#include "hevc.h" + #include "rtpenc.h" + #include "mov_chan.h" + +@@ -685,6 +686,16 @@ static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track) + return update_size(pb, pos); + } + ++static int mov_write_hvcc_tag(AVIOContext *pb, MOVTrack *track) ++{ ++ int64_t pos = avio_tell(pb); ++ ++ avio_wb32(pb, 0); ++ ffio_wfourcc(pb, "hvcC"); ++ ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 0); ++ return update_size(pb, pos); ++} ++ + /* also used by all avid codecs (dv, imx, meridien) and their variants */ + static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track) + { +@@ -741,6 +752,7 @@ static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track) + return 0; + + if (track->enc->codec_id == AV_CODEC_ID_H264) tag = MKTAG('a','v','c','1'); ++ else if (track->enc->codec_id == AV_CODEC_ID_HEVC) tag = MKTAG('h','e','v','1'); + else if (track->enc->codec_id == AV_CODEC_ID_AC3) tag = MKTAG('a','c','-','3'); + else if (track->enc->codec_id == AV_CODEC_ID_DIRAC) tag = MKTAG('d','r','a','c'); + else if (track->enc->codec_id == AV_CODEC_ID_MOV_TEXT) tag = MKTAG('t','x','3','g'); +@@ -1035,6 +1047,8 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) + mov_write_svq3_tag(pb); + else if (track->enc->codec_id == AV_CODEC_ID_DNXHD) + mov_write_avid_tag(pb, track); ++ else if (track->enc->codec_id == AV_CODEC_ID_HEVC) ++ mov_write_hvcc_tag(pb, track); + else if (track->enc->codec_id == AV_CODEC_ID_H264) { + mov_write_avcc_tag(pb, track); + if (track->mode == MODE_IPOD) +@@ -2925,6 +2939,15 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) + } else { + size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size); + } ++ } else if (enc->codec_id == AV_CODEC_ID_HEVC && trk->vos_len > 6 && ++ (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) { ++ /* extradata is Annex B, assume the bitstream is too and convert it */ ++ if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) { ++ ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data, &size, 0, NULL); ++ avio_write(pb, reformatted_data, size); ++ } else { ++ size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL); ++ } + } else { + avio_write(pb, pkt->data, size); + } |