Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
20b40a59
Commit
20b40a59
authored
Mar 03, 2014
by
Tim Walker
Committed by
Vittorio Giovara
Mar 09, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
movenc: write hvcC tag for HEVC.
parent
1d9014f0
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1140 additions
and
1 deletion
+1140
-1
Makefile
libavformat/Makefile
+1
-1
hevc.c
libavformat/hevc.c
+1076
-0
hevc.h
libavformat/hevc.h
+50
-0
movenc.c
libavformat/movenc.c
+13
-0
No files found.
libavformat/Makefile
View file @
20b40a59
...
...
@@ -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
...
...
libavformat/hevc.c
0 → 100644
View file @
20b40a59
/*
* Copyright (c) 2014 Tim Walker <tdskywalker@gmail.com>
*
* 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
(
gb
);
// scaling_list_dc_coef_minus8[i-2][j]
for
(
k
=
0
;
k
<
num_coeffs
;
k
++
)
get_se_golomb
(
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
(
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
(
gb
);
// pps_cb_qp_offset
get_se_golomb
(
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_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
;
}
libavformat/hevc.h
0 → 100644
View file @
20b40a59
/*
* Copyright (c) 2014 Tim Walker <tdskywalker@gmail.com>
*
* 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 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 */
libavformat/movenc.c
View file @
20b40a59
...
...
@@ -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
)
{
...
...
@@ -1035,6 +1046,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
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment