H.264 sequence_parameter_sets成员值含义学习笔记

本文详细解析了H.264标准中sequence parameter sets (SPS)的各项参数及其含义,涵盖profile_idc、constraint_set标志、level_idc等关键配置,帮助读者深入理解视频编码的基本设置。
H.264 sequence_parameter_sets成员值含义学习笔记
 

SPS: sequence parameter sets
它指的是码流对应的profile.
 
1.1 基线profile(Baseline profile)
遵循基线profile的码流应该遵循以下的约束:
 
a) 只有IP切片存在
b) NAL单元流不应该有范围在24nal_unit_type,包括24.
c) 序列参数集(sps)frame_mbs_only_fag(之后介绍)应该等于1
d) 图象参数值(psp)weighted_pred_flagweighted_bipred_idc都应该为0
e) 图象参数值(psp)entropy_coding_mode_flag应该等于0
f) 图象参数值(psp)num_slice_groups_minus1应该在07之间,包括07**psp部分参数含义在关于psp的文章中给出。
g) 对于基线profile对应的level度应该满足.
 
符合基线profile的码流的profile_idc被赋66.符合一定level的基线Baseline的解码器应该可以解码所有的profile_idc等于66的码流或constrained_set0_flag(等会介绍)1而且level_idc(level部分介绍)少于或等于一个指定的level的码流。
 
1.2 profile(Main profile)
符合主profile的码流应该遵循以下的约束:
 
a) 只有I,P,B切片存在.
b) NAL单元流不包括nal_unit_type值范围在2-4之内的值。包括24.
c) 不能允许有随意顺序的切片
d) 图像参数集(psp)num_slice_groups_minus1应该只为0
e) 图像参数集(psp)redundant_pic_cnt_present_flag应该只为0
f) 对于主profile所要求的level级需要达到。
 
符合主profile的码流的profile_idc应为77。符合指定level的主profile的解码器应该可以解码所有的profile_idc77的或constrained_set1_flag值为1level_idc值小于或等于指定level的码流。
 
1.3 扩展profile(Extended profile)
符合扩展profile的码流应该遵循以下的约束:
 
a) 序列参数集的direct_8x8_inference_flag值应该为1
b) 图像参数集的entropy_coding_mode_flag值应该为0
c) 图像参数集的num_slice_groups_minus1的值范围为07,包括07
d) 对于扩展profile指定的level级应该被达到
 
符合指定level级的扩展profile的解码器可以解码所有的profile_idc值为88的或constrained_set2_flag值为1的,而且level_idc小于等于指定level级的码流。
 
符合指定level级的扩展profile的解码器可以解码所有的profile_idc值为66的或constrained_set0_flag值为1的,而且level_idc小于等于指定level级的码流。
constrained_set0_flag值为1的时候,就说明码流应该遵循基线profile(Baseline profile)的所有约束.constrained_set0_flag值为0时,说明码流不一定要遵循基线profile的所有约束。
constrained_set1_flag值为1的时候,就说明码流应该遵循主profile(Main profile)的所有约束.constrained_set1_flag值为0时,说明码流不一定要遵循主profile的所有约束。
constrained_set2_flag值为1的时候,就说明码流应该遵循扩展profile(Extended profile)的所有约束.constrained_set2_flag值为0时,说明码流不一定要遵循扩展profile的所有约束。
注意:当constraint_set0_flag,constraint_set1_flagconstraint_set2_flag中不只一个值为1的话,那么码流必须满足所有相应指明的profile约束。
Reserved. Set to 0.
Reserved. Set to 0.
它指的是码流对应的level.
 
5.1 独立于profilelevel约束
fR是这样一个变量:
a) 如果图像n是一帧,fR设为1/172
b) 如果图像n是一个场,fR设为1/(172*2)
 
任何profile下的指定的level都应该满足如下约束:
a) 理论上可访问单元nCPB中的移除时间满足这样的约束:t(n)-t(n-1)要比Max(PicSizeInMbs,MaxMBPS,fR)值大或相等,MaxMBPS是说在level表中指出的对于图像n的值,PicSizeInMbs是指在图像n中的宏块数。
b) 如果图像n是一个输出图像而且它不是码流的最后一个输出图象,从DPB中取出的连续的输出图象差满足:Dt(n) >= Max(PicSizeInMbs, MaxMBPS, fR), MaxMBPS是指对于图象n来说的相应的值。PicSizeInMbs指图象n的宏块。
c) 对于可访问单元0NumBytesInNALunit变量的总和少于或等于256*ChromaFormatFactor*(PicSizeInMbs+MaxMBPS*tr(0)-trn(0)/MinCRMaxMBPSMinCR是图象0level表中相应的值,PicSizeInMbs是图象0的宏块数量。
d) 对于可访问单元nNumBytesInNALunit值的总和是小于或等于256*ChromaFormatFactor*MaxMBPS*(tr(n)-trn(n-1))/MinCR,MaxMBPSMinCR的值是图像nlevel级表中对应的值。
e) PicWidthInMbs * FrameHeightInMbs <= MaxFS, MaxFS是在level表中指定的值。
f) PicWidthInMbs <= Sqrt(MaxFS * 8)
g) FrameHeightInMbs <= Sqrt(MaxFS * 8)
h) max_dec_frame_buffering <=MaxDpbSize, MaxDpbSize等于Min(1024 * MaxDPB / (PicWidthInMbs * FrameHeightInMbs * 256 * ChromaFormatFactor,16)MaxDPB是对于1024字节单元的MaxDPB值,max_dec_frame_buffering也叫做DPB大小值。
i) 对于VCL HRD参数值,至少对于一个SchedSelIdx值来说,码率BitRate[SchedSelIdx] <= 1000 * MaxBRCpbSize[SchedSelIdx] <= 1000 * MaxCPBMaxBRMaxCPB是对于1000bits/s1000位单元对应于level级表的值。码流应该为0cpb_cnt_minus1中的一个值,包括0cpb_cnt_minus1.CpbSize[SchedSelIdx]也叫做CPB大小值。
j) 对于NAL HRD参数来说,BitRate[SchSelIdx] <= 1200 * MaxBRCpbSize[SchedSelIdx] <= 1200 * MaxCPBMaxBRMaxCPB是在1200bits/s1200位的单元值在极限level下的值。码流应该满足至少SchedSelIdx值从0cpb_cnt_minus1中的一个值。
k) 在亮度帧采样中,垂直运动向量元素范围不能超过MaxVmvRMaxVmvR值在level极限表中提供
l) 在亮度帧采样单元中,水平运动向量范围不能超过-20482047.75,包括-20482047.75
m) 按解码顺序的两个连续的宏愉的运动向量的数量不超过MaxMvsPer2Mb(对于当前宏块的最后一个切片和下一个宏块的第一个切片也适用),MaxMvsPer2Mb值在level极限表中提供.
n) 对于任何宏块的macroblock_layer()的位数值都不能大于128 + 2048 * ChromaFormatFactor.依赖于entropy_coding_mode_flag值,macroblock_layer()的值由如下方式计算
 如果entropy_coding_mode_flag值为0的话,macroblock_layer()的值由macroblock_layer()的对于一个macroblock的语法结构给出
 其他情况下,对于一个宏块的macroblock_layer()值是由read_bits(1)给出的.
5.2 profile相关的level
对于基线profile,profile和扩展profile的相应的level级约束在H.264的文档中有表可查。
seq_parameter_set_id指定了由图像参数集指明的序列参数集。seq_parameter_set_id值应该是从031,包括031
注意:当可用的情况下,编码器应该在sps值不同的情况下使用不同的seq_parameter_set_id值,而不是变化某一特定值的seq_parameter_set_id的参数集的语法结构中的值。
log2_max_frame_num_minus4指定了变量MaxFrameNum的值, MaxFrameNum = 2(log2_max_frame_num_minus4+4)
log2_max_frame_num_minus的值应该在012之间,包括012.
pic_order_cnt_type指定了解码图像顺序的方法。pic_order_cnt_type的值是0,1,2
pic_order_cnt_type在当一个编码视频序列有如下限定时不为2
a) 包含非参考帧的可访问单元,并紧接着一个包含非参考可访问单元
b) 两个可访问单元,它们分别包含两个场中的一个,它们一块儿组成了一个互补的非参考场对,被紧接着一个包括非参考图像的可访问单元。
c) 一个包含非参考场的可访问单元,并紧接着一个包含另一个非参考图像的可访问单元,它们不组成互补的非参考场对。
log2_max_pic_order_cnt_lsb_minus4指出变量MaxPicOrderCntLsb的值,它是在解码过程中使用到的图像顺序计算值:
MaxPicOrderCntLsb = 2(log2_max_pic_order_cnt_lsb_minus4+4)
log2_max_pic_order_cnt_lsb_minus4的值为包括012以及它们之间的值。
delta_pic_order_always_zero_flag等于1的时候表示当delta_pic_order_cnt[0]delta_pic_order_cnt[1]在序列的切片头中不存在,并被认为是0
delta_pic_order_always_zero_flag值等于0时表示delta_pic_order_cnt[0]在序列的切片头中存在而delta_pic_order_cnt[1]可能在序列的切片头中存在。
offset_for_non_ref_pic被用来计算一个非参考图像的图像顺序值。offset_for_non_ref_pic值取值范围为(-2)^(31)2^(31)-1,包括边界值。
offset_for_top_to_bottom_field被用来计算一帧中的下场的图像顺序值。
offset_for_top_to_bottom_field值的取值范围为(-2)^(31)(2)^(31)-1,包括边界值。
num_ref_frames_in_pic_order_cnt_cycle在解码过程中被用来计算图像顺序值。
num_ref_frames_in_pic_order_cnt_cycle0255之间取值,包括边界值。
offset_for_ref_frame[i]是一列num_ref_frames_in_pic_order_cnt_cycle中的一个元素,它被在解码过程的解码顺序值中使用。
offset_for_ref_frame[i]的值为(-2)^31(2)^(31)-1,包括边界值。
num_ref_frames指定了长期的和短期的参考帧的最大总数目,互补的参考场对和在解码过程。
gaps_in_frame_num_value_allowed_flag值指明了frame_num允许的值和解码过程中的frame_num的差距值。
pic_width_in_mbs_minus11指明了对于每个解码图像中的宽度值。在宏块单元中的图像宽度的变量值为:
PicWidthInMbs = pic_width_in_mbs_minus1+1;
对于亮度元素来说图像宽度变量的值:
PicWidthInSamplesL = PicWidthInMbs * 16;
对于色度元素来说图像宽度变量的值:
PicWidthInSamplesC = PicWidthInMbs * 8;
pic_height_in_map_units_minus1指明了解码帧或场中的一个切片组的高度。变量PicHeightInMapUnits的值和PicSizeInMapUnits
PicHeightInMapUnits = pic_height_in_map_units_minus1 + 1;
PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits
frame_mbs_only_flag等于0指明了视频序列的编码图象可能是编码场或编码帧。frame_mbs_only_flag等于1指明了每个编码视频序列的编码图像都是只含帧宏块的编码帧。
依赖于frame_mbs_only_flag的值,pic_height_in_map_units_minus1如下定义:
frame_mbs_only_flag等于0pic_height_in_map_units_minus1就是宏块单元的场高
frame_mbs_only_flag等于1pic_height_in_map_units_minus1就是宏块单元的场宽
FrameHeightInMbs的值:
FrameheightInMbs = ( 2 - frame_mbs_only_flag ) * PicHeightInMapUnits
mb_adaptive_frame_field_flag等于0表明在一个图像内不能切换使用帧和场宏块。
mb_adaptive_frame_field_flag等于1表示在一帧中有可能使用场和帧的切换,当mb_adaptive_frame_field_flag没有设定的时候,应该赋给0.
direct_8x8_inference_flag指明了在亮度运动向量生成B_SkipB_Direct_16x16B_Direct_8x8的方法。
frame_mbs_only_flag0时,direct_8x8_inference_flag应为1
frame_cropping_flag等于1表明在sps中下一个使用的帧剪切偏移量参数。frame_cropping_flag等于0表明帧剪切偏移量不存在。
指明了在一个窗中一帧的采样值。
vui_parameters_present_flag等于1表示vui_parameters()在码流中是存在的,vui_parameters_present_flag等于0表明vui_parameters()在码流中不存在。
rbsp_stop_one_bit        恒等于1
rbsp_alignment_zero_bit      恒等于0.
Note:
       More detail need refer to
       1). Advanced video coding for generic audiovisual services.pdf P63.
       2). Refer to ISOIEC 14496-10-2005-PDAM 3.doc P40
 
 
rbsp_trailing_bits( ) {
C
Descriptor
    rbsp_stop_one_bit /* equal to 1 */
All
f(1)
    while( !byte_aligned( ) )
 
 
       rbsp_alignment_zero_bit /* equal to 0 */
All
f(1)
}
 
 
 
seq_parameter_set_rbsp( ) {
C
Descriptor
    profile_idc
0
u(8)
    constraint_set0_flag
0
u(1)
    constraint_set1_flag
0
u(1)
    constraint_set2_flag
0
u(1)
    constraint_set3_flag
0
u(1)
    reserved_zero_4bits /* equal to 0 */
0
u(4)
    level_idc
0
u(8)
    seq_parameter_set_id
0
ue(v)
    if( profile_idc = = 83 ) {
 
 
       seq_parameter_set_svc_extension( ) /* specified in Annex F */
 
 
    }
 
 
    if( profile_idc = = 100 | | profile_idc = = 110 | |
        profile_idc = = 122 | | profile_idc = = 144  | |
        profile_idc = = 83 ) {
 
 
       chroma_format_idc
0
ue(v)
       if( chroma_format_idc = = 3 )
 
 
           residual_colour_transform_flag
0
u(1)
       bit_depth_luma_minus8
0
ue(v)
       bit_depth_chroma_minus8
0
ue(v)
       qpprime_y_zero_transform_bypass_flag
0
u(1)
       seq_scaling_matrix_present_flag
0
u(1)
       if( seq_scaling_matrix_present_flag )
 
 
           for( i = 0; i < 8; i++ ) {
 
 
               seq_scaling_list_present_flag[ i ]
0
u(1)
               if( seq_scaling_list_present_flag[ i ] )
 
 
                  if( i < 6 )
 
 
                      scaling_list( ScalingList4x4[ i ], 16, 
                                       UseDefaultScalingMatrix4x4Flag[ i ])
0
 
                  else
 
 
                      scaling_list( ScalingList8x8[ i – 6 ], 64,
                                       UseDefaultScalingMatrix8x8Flag[ i – 6 ] )
0
 
           }
 
 
    }
 
 
    log2_max_frame_num_minus4
0
ue(v)
    pic_order_cnt_type
0
ue(v)
    if( pic_order_cnt_type = = 0 )
 
 
       log2_max_pic_order_cnt_lsb_minus4
0
ue(v)
    else if( pic_order_cnt_type = = 1 ) {
 
 
0
u(1)
       offset_for_non_ref_pic
0
se(v)
       offset_for_top_to_bottom_field
0
se(v)
       num_ref_frames_in_pic_order_cnt_cycle
0
ue(v)
       for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
 
 
           offset_for_ref_frame[ i ]
0
se(v)
    }
 
 
    num_ref_frames
0
ue(v)
    gaps_in_frame_num_value_allowed_flag
0
u(1)
    pic_width_in_mbs_minus1
0
ue(v)
    pic_height_in_map_units_minus1
0
ue(v)
    frame_mbs_only_flag
0
u(1)
    if( !frame_mbs_only_flag )
 
 
       mb_adaptive_frame_field_flag
0
u(1)
    direct_8x8_inference_flag
0
u(1)
    frame_cropping_flag
0
u(1)
    if( frame_cropping_flag ) {
 
 
       frame_crop_left_offset
0
ue(v)
       frame_crop_right_offset
0
ue(v)
       frame_crop_top_offset
0
ue(v)
       frame_crop_bottom_offset
0
ue(v)
    }
 
 
    vui_parameters_present_flag
0
u(1)
    if( vui_parameters_present_flag )
 
 
       vui_parameters( )
0
 
    rbsp_trailing_bits( )
0
 
}
 
 
<think> 我们正在讨论的是在Flink Connector for Doris中设置序列列(sequence column)的配置。序列列用于解决UNIQUE KEY模型下数据更新的顺序问题。 用户给出的配置项是:'sink.properties.function_column.sequence_col'='etl_sequence' 这个配置项的作用是告诉Doris,在数据导入时使用指定的列(这里是etl_sequence)作为序列列,以保证相同主键的数据按照序列列的进行更新(大的覆盖小的)。 但是,根据用户提供的建表语句,我们注意到在Doris表的PROPERTIES中已经设置了: "function_column.sequence_type" = "bigint" 而这里在Flink的Doris Sink配置中又设置了: 'sink.properties.function_column.sequence_col' = 'etl_sequence' 这两者是否冲突?实际上,它们的作用是不同的: 1. Doris建表属性中的`function_column.sequence_type`(注意:这个属性在Doris中实际不存在,正确属性应为`function_column.sequence_col`): 在Doris中,我们通常是在建表时通过`PROPERTIES`设置序列列,例如: "function_column.sequence_col" = 'etl_sequence' 注意:在Doris中,这个属性是用于指定表中哪个列作为序列列,并且这个列必须存在于表中。 2. 在Flink Doris Connector中,我们通过`sink.properties.function_column.sequence_col`来指定序列列,这个会作为Stream Load的一个参数传递给Doris,告诉Doris本次导入使用哪个列作为序列列。 因此,如果我们在建表时已经指定了序列列,那么在Flink Connector中也需要指定相同的序列列,这样数据导入时才能正确使用。 但是,用户提供的建表语句中设置的是`"function_column.sequence_type" = "bigint"`,这可能是错误的,因为Doris中并没有`function_column.sequence_type`这个属性。正确的属性名是`function_column.sequence_col`。 因此,我们需要修正建表语句中的属性,将其改为: "function_column.sequence_col" = "etl_sequence" 同时,在Flink Connector中配置: 'sink.properties.function_column.sequence_col' = 'etl_sequence' 这样两者就一致了。 另外,在Flink Connector中,我们也可以通过这个参数动态指定序列列,即使表属性中没有设置,只要表是UNIQUE KEY模型且支持序列列(Doris版本>0.15),也可以通过Stream Load参数指定。 所以,回答用户的问题:这个配置项是正确的,但需要确保Doris表属性也正确设置了序列列(使用正确的属性名)。 下面给出完整的配置示例(Flink SQL方式): ```sql CREATE TABLE doris_sink ( ... -- 字段列表 ) WITH ( 'connector' = 'doris', 'fenodes' = 'doris-fe:8030', 'table.identifier' = 'database.table', 'username' = 'user', 'password' = 'pass', 'sink.label-prefix' = 'flink_label', -- 每次导入的label前缀,应保证唯一性(通常配合随机后缀) 'sink.properties.column_separator' = '\x01', -- 列分隔符,可选 'sink.properties.row_delimiter' = '\n', -- 行分隔符,可选 'sink.properties.format' = 'csv', -- 也可以是json -- 以下是序列列配置 'sink.properties.function_column.sequence_col' = 'etl_sequence' ); ``` 注意事项: 1. 序列列必须在Doris表中存在,且类型为数类型(如BIGINT)或时间类型(如DATETIME)。 2. 在Flink Connector中配置序列列,只对当前这个sink生效,不影响表本身的其他导入任务。 3. 如果同时在建表属性中设置了序列列,那么需要保证两者一致,否则以Stream Load参数(即Flink配置)为准。 因此,用户需要检查并修正建表语句中的属性,然后确保Flink Connector中配置的序列列与表结构中的列名一致。 §§相关问题§§ 1. 如果Doris表中没有设置序列列属性,仅通过Flink Connector的sink.properties.function_column.sequence_col参数指定序列列,是否生效? 2. 当序列列(etl_sequence)的相同或为空时,Doris会如何处理相同主键的数据? 3. 在Flink Connector中配置序列列时,是否支持使用计算列(如使用Flink SQL表达式生成的列)作为序列列? 4. 对于Doris的Duplicate Key模型,设置序列列是否有效?为什么? 5. 如何验证序列列在数据更新过程中确实按照预期工作? </think>### Flink Doris Connector 序列列配置详解 在 Flink Doris Connector 中使用 `sink.properties.function_column.sequence_col='etl_sequence'` 是 **解决 UNIQUE KEY 模型数据更新的核心配置**。以下是深度解析和最佳实践: --- ### 序列列工作原理 ```mermaid graph LR A[Flink数据流] -->|携带etl_sequence| B(Doris Sink) B --> C{比较版本号} C -->|etl_sequence_new > 当前| D[覆盖旧数据] C -->|etl_sequence_new ≤ 当前| E[丢弃新数据] ``` #### 关键特性: 1. **版本控制**:相同主键的数据按 `etl_sequence` 降序保留最新版本 2. **乱序处理**:允许数据乱序到达,自动按序列号排序 3. **删除标记**:通过设置 `etl_sequence=0` 可软删除数据(需配合 `merge_type=DELETE`) --- ### 完整配置示例 ```java DorisSink.<Row>sinkBuilder() .setDorisOptions(options) .setDorisExecutionOptions( DorisExecutionOptions.builder() .setStreamLoadProp("format", "json") .setStreamLoadProp("read_json_by_line", "true") // 核心序列列配置 .setStreamLoadProp("function_column.sequence_col", "etl_sequence") // 删除操作配置 .setStreamLoadProp("merge_type", "MERGE") .setStreamLoadProp("delete", "etl_record_type=2") .build() ) .setSerializer(new SimpleRowSerializer(schema)) .build(); ``` --- ### 三大使用场景及配置方案 #### 场景1:基于时间戳的更新 ```java // 生成毫秒级时间戳序列号 .map(row -> { row.setField("etl_sequence", System.currentTimeMillis()); return row; }) ``` **适用场景**:实时增量数据同步 #### 场景2:基于版本号的更新 ```sql -- Doris表中添加版本管理列 ALTER TABLE ods_user_biz_operate_log_1 ADD COLUMN data_version BIGINT DEFAULT 0; ``` ```java // Flink中递增版本号 .state(new ValueStateDescriptor<>("version", Long.class)) .process((row, ctx) -> { Long version = state.value(); row.setField("etl_sequence", version + 1); state.update(version + 1); return row; }) ``` **适用场景**:有严格版本顺序的业务系统 #### 场景3:删除操作实现 ```java // 标记删除数据 .filter(row -> row.getField("is_deleted") == null) .map(row -> { if (row.getField("op_type").equals("DELETE")) { row.setField("etl_sequence", 0); // 触发删除 } return row; }) ``` **配置联动**: ```properties setStreamLoadProp("merge_type", "MERGE") setStreamLoadProp("delete", "etl_sequence=0") ``` --- ### 常见问题解决方案 #### 问题1:序列列重复导致数据覆盖 **解决方案**:组合主键+序列列 ```java // 生成唯一序列 row.setField("etl_sequence", System.currentTimeMillis() + ThreadLocalRandom.current().nextInt(1000) ); ``` #### 问题2:历史数据迁移时序列号冲突 **解决方案**:批次范围隔离 ```sql -- Doris临时调整序列列范围 ALTER TABLE ods_user_biz_operate_log_1 SET ("function_column.sequence_range" = "1000000-2000000"); ``` #### 问题3:Flink重启后序列号不连续 **解决方案**:Checkpoint状态恢复 ```java env.enableCheckpointing(5000); env.getCheckpointConfig().setCheckpointStorage("hdfs:///checkpoints"); ``` --- ### 性能优化参数 ```java .setStreamLoadProp("timeout", "1200") // 超时时间延长至20分钟 .setStreamLoadProp("max_filter_ratio", "0.3") // 允许30%过滤 .setStreamLoadProp("load_mem_limit", "2147483648") // BE内存限制2GB ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值