x264_param_t

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
typedef struct x264_param_t
{
/* ========== CPU 相关 ========== */
uint32_t cpu; /* CPU 标志位,指定使用的指令集优化(如 SSE、AVX 等) */
int i_threads; /* 并行编码的线程数,0=自动检测,1=单线程 */
int i_lookahead_threads; /* 用于前瞻分析(lookahead)的线程数 */
int b_sliced_threads; /* 是否使用基于条带(slice)的线程模式,而非帧级线程 */
int b_deterministic; /* 多线程时是否禁用非确定性优化,确保每次编码结果完全一致 */
int b_cpu_independent; /* 强制使用规范行为,而非依赖 CPU 的最优算法 */
int i_sync_lookahead; /* 前瞻缓冲区的同步大小,0=不使用同步 */

/* ========== 视频属性 ========== */
int i_width; /* 视频宽度(像素) */
int i_height; /* 视频高度(像素) */
int i_csp; /* 输入图像的色彩空间格式,如 X264_CSP_I420、X264_CSP_YUYV 等 */
int i_bitdepth; /* 像素位深,8 或 10 */
int i_level_idc; /* H.264 级别(Level),如 41 表示 Level 4.1,0=自动 */
int i_frame_total; /* 总编码帧数,已知时设置,0=未知 */

/* ========== NAL HRD(假想参考解码器)========== */
/* 使用缓冲和图像定时 SEI 来信号 HRD 信息
* 注意:HRD 并非为可变帧率(VFR)设计,不建议与 VFR 一起使用
* 此外,通过 x264_encoder_reconfig 重配置 VBV 会导致 HRD 无效 */
int i_nal_hrd; /* NAL HRD 信息模式:0=无,1=有,2=有且为 CBR */

/* ========== VUI(视频可用性信息)========== */
struct
{
/* 像素宽高比(SAR),会被调整为 0 < x <= 65535 且为质数 */
int i_sar_height; /* SAR 高度 */
int i_sar_width; /* SAR 宽度 */

int i_overscan; /* 过扫描:0=未定义,1=无过扫描,2=有过扫描 */

/* 以下参见 H.264 附录 E 的定义 */
int i_vidformat; /* 视频格式:0=未定义,1=隔行,2=逐行,3=逐行(HD)等 */
int b_fullrange; /* 是否全范围:0=有限范围(16-235),1=全范围(0-255) */
int i_colorprim; /* 色彩原色:如 BT.709、BT.601 等 */
int i_transfer; /* 传输特性:如 BT.709、Gamma 等 */
int i_colmatrix; /* 色彩矩阵系数:如 BT.709、BT.601 等 */
int i_chroma_loc; /* 色度采样位置(顶部和底部相同) */
} vui;

/* ========== 码流参数 ========== */
int i_frame_reference; /* 最大参考帧数量(DPB 中参考帧数),影响压缩效率和内存占用 */
int i_dpb_size; /* 强制 DPB(解码图像缓冲区)大于 B 帧和参考帧隐含的大小 */
int i_keyint_max; /* IDR 关键帧最大间隔(帧数),GOP 大小 */
int i_keyint_min; /* 场景切换小于此间隔时编码为 I 帧而非 IDR 帧 */
int i_scenecut_threshold; /* 场景切换检测阈值,值越大越激进地插入额外 I 帧,0=禁用 */
int b_intra_refresh; /* 是否使用周期性帧内刷新替代 IDR 帧(用于低延迟场景) */

int i_bframe; /* 两个参考帧之间的 B 帧数量(最大连续 B 帧数) */
int i_bframe_adaptive; /* B 帧自适应模式:0=关,1=快速,2=最优(提升 B 帧放置质量) */
int i_bframe_bias; /* B 帧偏向性(-100~100),正数倾向于多用 B 帧 */
int i_bframe_pyramid; /* B 帧金字塔结构:0=关,1=严格分层,2=普通(允许 B 帧作为参考) */
int b_open_gop; /* 是否使用开放 GOP(允许从前一个 GOP 参考,提高压缩率) */
int b_bluray_compat; /* Blu-ray 兼容模式,强制符合 Blu-ray 标准限制 */
int i_avcintra_class; /* AVC-Intra 类别(50/100/200) */
int i_avcintra_flavor; /* AVC-Intra 变体(0=标准,1=Panasonic 变体) */

int b_deblocking_filter; /* 是否启用去块效应滤波器 */
int i_deblocking_filter_alphac0; /* 去块强度 AlphaC0 参数(-6 ~ 6),负值=轻滤波,正值=强滤波 */
int i_deblocking_filter_beta; /* 去块强度 Beta 参数(-6 ~ 6) */

int b_cabac; /* 是否使用 CABAC 熵编码(否为 CAVLC) */
int i_cabac_init_idc; /* CABAC 初始上下文表索引(0~2) */

int b_interlaced; /* 是否为隔行扫描视频 */
int b_constrained_intra; /* 是否使用受限帧内预测(仅参考帧内宏块) */

/* ========== 量化矩阵(CQM)========== */
int i_cqm_preset; /* 自定义量化矩阵预设:X264_CQM_FLAT(平坦)、X264_CQM_JVT(默认)、X264_CQM_CUSTOM(自定义) */
char *psz_cqm_file; /* CQM 文件名(UTF-8 编码),JM 格式 */
uint8_t cqm_4iy[16]; /* 4x4 帧内 Y 自定义矩阵,仅在 i_cqm_preset == X264_CQM_CUSTOM 时使用 */
uint8_t cqm_4py[16]; /* 4x4 帧间 Y 自定义矩阵 */
uint8_t cqm_4ic[16]; /* 4x4 帧内 Cb/Cr 自定义矩阵 */
uint8_t cqm_4pc[16]; /* 4x4 帧间 Cb/Cr 自定义矩阵 */
uint8_t cqm_8iy[64]; /* 8x8 帧内 Y 自定义矩阵 */
uint8_t cqm_8py[64]; /* 8x8 帧间 Y 自定义矩阵 */
uint8_t cqm_8ic[64]; /* 8x8 帧内 Cb/Cr 自定义矩阵 */
uint8_t cqm_8pc[64]; /* 8x8 帧间 Cb/Cr 自定义矩阵 */

/* ========== 日志 ========== */
void (*pf_log)( void *, int i_level, const char *psz, va_list ); /* 自定义日志回调函数 */
void *p_log_private; /* 日志回调的私有数据指针 */
int i_log_level; /* 日志级别:X264_LOG_DEBUG、X264_LOG_INFO、X264_LOG_ERROR 等 */
int b_full_recon; /* 是否完全重建图像(即使编码不需要),设置 psz_dump_yuv 时隐含启用 */
char *psz_dump_yuv; /* 重建帧输出文件名(UTF-8),用于调试分析 */

/* ========== 编码器分析参数 ========== */
struct
{
unsigned int intra; /* 帧内分区模式(如 X264_PART_I4x4、X264_PART_I8x8、X264_PART_I16x16) */
unsigned int inter; /* 帧间分区模式(如 X264_PART_P8x8、X264_PART_P4x4、X264_PART_B8x8) */

int b_transform_8x8; /* 是否允许 8x8 变换(需 Profile >= High) */
int i_weighted_pred; /* P 帧加权预测:0=关,1=简单加权,2=智能加权 */
int b_weighted_bipred; /* B 帧隐式加权预测(用于亮度补偿) */
int i_direct_mv_pred; /* 直接 MV 预测模式:0=空间预测,1=时间预测,2=自动选择 */
int i_chroma_qp_offset; /* 色度 QP 偏移量(-12 ~ 12),影响色度画质 */

int i_me_method; /* 运动估计算法:X264_ME_DIA(菱形)、X264_ME_HEX(六边形)、X264_ME_UMH、X264_ME_ESA(全搜索)、X264_ME_TESA */
int i_me_range; /* 整数像素运动估计搜索范围(像素) */
int i_mv_range; /* 运动向量最大长度(像素),-1=自动基于 Level 决定 */
int i_mv_range_thread; /* 线程间最小空间间隔,-1=自动基于线程数决定 */
int i_subpel_refine; /* 亚像素运动估计质量(0~11),值越大越精细,耗时越多 */
int b_chroma_me; /* P 帧亚像素和模式决策时是否进行色度 ME */
int b_mixed_references; /* 是否允许每个宏块分区使用独立参考帧 */
int i_trellis; /* Trellis RD 量化:0=关,1=仅在最后量化时启用,2=始终启用 */
int b_fast_pskip; /* P 帧快速 SKIP 检测(在 P 帧中快速检测无运动宏块) */
int b_dct_decimate; /* P 帧 DCT 系数阈值处理(裁剪不重要的系数) */
int i_noise_reduction; /* 自适应伪死区降噪强度 */
float f_psy_rd; /* Psy(心理视觉)RD 优化强度,改善主观画质 */
float f_psy_trellis; /* Psy Trellis 强度 */
int b_psy; /* 总开关:启用所有 Psy 优化 */

int b_mb_info; /* 是否使用 x264_picture_t 中输入的 mb_info 数据 */
int b_mb_info_update; /* 是否根据编码结果更新 mb_info 值 */

/* 亮度量化死区大小 */
int i_luma_deadzone[2]; /* {帧间, 帧内} */

int b_psnr; /* 是否计算并打印 PSNR 统计 */
int b_ssim; /* 是否计算并打印 SSIM 统计 */
} analyse;

/* ========== 码率控制参数 ========== */
struct
{
int i_rc_method; /* 码率控制方式:X264_RC_CQP(固定 QP)、X264_RC_CRF(恒定质量)、X264_RC_ABR(平均码率) */

int i_qp_constant; /* 固定 QP 值(0=无损) */
int i_qp_min; /* 最小允许 QP 值 */
int i_qp_max; /* 最大允许 QP 值 */
int i_qp_step; /* 帧间最大 QP 变化步长 */

int i_bitrate; /* 目标码率(kbps),用于 ABR 模式 */
float f_rf_constant; /* CRF 值(0~51),CRF 模式下使用,值越低质量越高 */
float f_rf_constant_max; /* VBV 约束下的最大 CRF 值 */
float f_rate_tolerance; /* 码率容差(倍数),允许码率波动的范围 */
int i_vbv_max_bitrate; /* VBV 最大码率(kbps) */
int i_vbv_buffer_size; /* VBV 缓冲区大小(kbit) */
float f_vbv_buffer_init; /* VBV 缓冲区初始填充度:<=1 为缓冲区比例,>1 为 kbit */
float f_ip_factor; /* I 帧相对于 P 帧的 QP 偏移因子 */
float f_pb_factor; /* B 帧相对于 P 帧的 QP 偏移因子 */

/* VBV 填充:强制 CBR VBV 并使用填充字节确保硬 CBR,NAL-HRD CBR 隐含启用 */
int b_filler;

int i_aq_mode; /* 自适应量化模式:X264_AQ_NONE(关)、X264_AQ_VARIANCE(方差)、X264_AQ_AUTOVARIANCE(自动)、X264_AQ_AUTOVARIANCE_BIASED */
float f_aq_strength; /* AQ 强度,1.0=标准 */
int b_mb_tree; /* 是否启用宏块树码率控制 */
int i_lookahead; /* 前瞻帧数,用于 MB-Tree 和 VBV */

/* 2 次编码 */
int b_stat_write; /* 是否启用统计信息写入 */
char *psz_stat_out; /* 2 次编码统计文件输出名(UTF-8) */
int b_stat_read; /* 是否从统计文件读取 */
char *psz_stat_in; /* 2 次编码统计文件输入名(UTF-8) */

/* 2 次编码参数(与 ffmpeg 相同) */
float f_qcompress; /* QP 压缩系数:0.0=完全 CBR,1.0=恒定 QP */
float f_qblur; /* 时间域 QP 模糊(平滑 QP 变化) */
float f_complexity_blur; /* 时间域复杂度模糊 */
x264_zone_t *zones; /* 码率控制区域覆盖(按帧范围设置不同参数) */
int i_zones; /* zone_t 数量 */
char *psz_zones; /* 区域定义的替代字符串方式 */
} rc;

/* ========== 裁剪矩形 ========== */
/* 由非 16 倍数字视频分辨率隐式定义的裁剪矩形补充 */
struct
{
int i_left; /* 左侧裁剪像素数 */
int i_top; /* 顶部裁剪像素数 */
int i_right; /* 右侧裁剪像素数 */
int i_bottom; /* 底部裁剪像素数 */
} crop_rect;

/* ========== 帧打包排列标志 ========== */
int i_frame_packing; /* 帧打包排列类型(用于立体/3D 视频),参见 H.264 附录 D */

/* ========== 母版显示 SEI(HDR)========== */
/* 主色和白色点色度坐标,单位为 0.00002 增量。亮度单位为 0.0001 cd/m² */
struct
{
int b_mastering_display; /* 是否写入母版显示 SEI */
int i_green_x; /* 绿色主色 X 坐标 */
int i_green_y; /* 绿色主色 Y 坐标 */
int i_blue_x; /* 蓝色主色 X 坐标 */
int i_blue_y; /* 蓝色主色 Y 坐标 */
int i_red_x; /* 红色主色 X 坐标 */
int i_red_y; /* 红色主色 Y 坐标 */
int i_white_x; /* 白色点 X 坐标 */
int i_white_y; /* 白色点 Y 坐标 */
int64_t i_display_max; /* 最大显示亮度(单位:0.0001 cd/m²) */
int64_t i_display_min; /* 最小显示亮度(单位:0.0001 cd/m²) */
} mastering_display;

/* ========== 内容光照级别 SEI(HDR)========== */
struct
{
int b_cll; /* 是否写入内容光照级别 SEI */
int i_max_cll; /* 最大内容亮度级别(单位:cd/m²) */
int i_max_fall; /* 最大帧平均亮度级别(单位:cd/m²) */
} content_light_level;

/* ========== 替代传输 SEI ========== */
int i_alternative_transfer; /* 替代传输特性(用于 HDR 兼容性) */

/* ========== 封装参数 ========== */
int b_aud; /* 是否生成访问单元分隔符(AUD)NAL */
int b_repeat_headers; /* 是否在每个关键帧前重复 SPS/PPS */
int b_annexb; /* 是否使用 Annex B 格式(起始码 4 字节),否则使用长度前缀(4 字节) */
int i_sps_id; /* SPS 和 PPS 的 ID 编号 */

int b_vfr_input; /* 是否输入为可变帧率(VFR):1=使用时间基和时间戳,0=仅使用 fps */
int b_pulldown; /* 是否使用显式设置的时间基进行 CFR(恒定帧率) */
uint32_t i_fps_num; /* 帧率分子 */
uint32_t i_fps_den; /* 帧率分母 */
uint32_t i_timebase_num; /* 时间基分子 */
uint32_t i_timebase_den; /* 时间基分母 */

int b_tff; /* 是否为顶场优先(Top Field First),用于隔行视频 */

/* ========== Pulldown(2:3 下拉变换)========== */
/* 必须为每个输入帧传递正确的 pic_struct
* 输入时间基应对应输出帧率的时间基,且必须恒定
* 例如:3:2 pulldown 时间基应为 1001/30000
* 每帧传入的 PTS 必须是 pulldown 应用后的 PTS
* 帧加倍和帧三倍需要设置 b_vfr_input=0(参见 H.264 表 D-1)
* Pulldown 变化在 H.264 中没有明确定义,因此由调用程序负责管理 */
int b_pic_struct; /* 是否使用图片结构(pic_struct)信息 */

/* ========== 伪隔行 ========== */
/* 仅当 b_interlaced=0 时使用。设置此标志可将码流标记为 PAFF 隔行,
* 但所有帧都按逐行编码。用于编码 25p 和 30p 的 Blu-ray 码流 */
int b_fake_interlaced;

/* ========== 可拼接模式 ========== */
/* 不基于视频内容优化头参数,确保分割视频分别压缩后拼接回 SPS/PPS 完全一致。
* 用于不支持多个 SPS/PPS 的封装格式拼接 */
int b_stitchable;

/* ========== OpenCL 加速 ========== */
int b_opencl; /* 是否在可用时使用 OpenCL 加速 */
int i_opencl_device; /* 指定跳过的 GPU 设备数量(CLI 用户使用) */
void *opencl_device_id; /* 显式传递 cl_device_id(API 用户使用,void* 类型) */
char *psz_clbin_file; /* 编译好的 OpenCL 内核缓存文件名(UTF-8) */

/* ========== 条带(Slice)参数 ========== */
int i_slice_max_size; /* 每个条带最大字节数(包含估计的 NAL 开销) */
int i_slice_max_mbs; /* 每个条带最大宏块数,覆盖 i_slice_count */
int i_slice_min_mbs; /* 每个条带最小宏块数 */
int i_slice_count; /* 每帧条带数:强制使用矩形条带划分 */
int i_slice_count_max; /* 每帧条带绝对上限,达到后不再应用 i_slice_max_size 和 i_slice_max_mbs */

/* ========== 参数释放回调 ========== */
/* 可选回调:当 x264_param_t 不再使用时释放它。
* 仅在 x264_param_t 长期存在于内存中时使用(如 x264_picture_t 或 zone 中的参数)。
* 调用 x264_encoder_reconfig 时不会使用此回调。 */
void (*param_free)( void* );

/* ========== 低延迟 NAL 输出回调 ========== */
/* 可选的底层回调,用于低延迟编码。每个 NAL 单元编码完成后立即调用。
* 允许应用在帧完全编码完成前就开始处理视频数据(如网络发送)。
*
* 此回调必须满足以下条件才能正确工作:
* 1) 准备一个至少为 nal->i_payload*3/2 + 5 + 64 字节的输出缓冲区
* 2) 调用 x264_nal_encode(h, dst, nal),dst 为输出缓冲区
* 完成后,nal 的内容可像 x264_encoder_encode 输出那样正常使用。
*
* 不必与编码过程同步:nal 指向的数据在下次 x264_encoder_encode 调用前保持有效。
* 回调必须是可重入的。
*
* 此回调不适用于基于帧的线程;必须禁用线程或启用基于条带的线程。
* HRD 行为异常:由于缓冲周期 SEI 需在帧编码完成后才能计算,不会通过此回调发送。
*
* 注意:启用条带线程时,NAL 不一定按顺序返回。
* x264_nal_t 中的 i_first_mb 和 i_last_mb 可帮助调用程序重新排序条带。
*
* 启用此回调后,x264_encoder_encode 不返回有效的 NAL;
* 调用程序应通过此回调获取所有输出的 NAL。
*
* 通常建议将此回调与 slice-max-mbs 或 slice-max-size 结合使用。
*
* opaque 指针是关联输入帧中的 opaque 指针,用于区分不同来源的 nalu_process 调用。
*/
void (*nalu_process)( x264_t *h, x264_nal_t *nal, void *opaque );

/* ========== 内部使用 ========== */
void *opaque; /* 仅供 x264 内部使用 */
} x264_param_t;

申请关键帧

1
2
3
4
5
6
7
8
9
10
11
12
x264_picture_t pic_in, pic_out;
// ... 此处省略其他参数和图像数据的初始化

// 强制当前帧编码为关键帧
pic_in.i_type = X264_TYPE_KEYFRAME;

// 执行编码,这将会输出一个关键帧
int frame_size = x264_encoder_encode(encoder, &nals, &i_nal, &pic_in, &pic_out);

// 编码完成后,将类型重置,让编码器继续自动决定后续帧的类型
// 如果不重置,后续所有帧都会被强制编码为关键帧,会导致码率激增
pic_in.i_type = X264_TYPE_AUTO;
X264_TYPE_I I帧, 自己不再参考前面的帧,但是后续的P帧有可能会去参考这个I帧之前的帧
X264_TYPE_IDR IDR帧,自己不再参考前面的帧,并且清空参考帧缓冲区,保证生成一个随机访问点
X264_TYPE_KEYFRAME 根据b_open_gop字段,自动选择生成I帧还是IDR帧

H.264 与 x264

H.264 Profiles

Wikipedia - Advanced Video Coding - Profiles

H.264 包含多个不同的 Profile, 用于适应不同的应用需求:

Baseline Profile

适合低成本和早期的移动设备使用, 目前已经很少采用

主要用于低成本应用, 对播放设备的性能要求不高, 此 profile 常见用于早期性能较低的行动设备 (如 Apple iPod)。现今行动设备性能比起以前强大许多, 此 profile 已经没有什么必要性了

Main Profile

早期用于电视广播, 现今应用不多

此 profile 原本是用于 SD 分辨率数码电视广播, 虽然没有实行, 然而被用于 HD 分辨率的电视广播。在 2004 年 High Profile 被开发之后, 此 profile 已经没有什么必要性了

早期的高性能行动播放设备(如 Sony PSP), 也是使用此 profile

High Profile

广泛用于 HD 应用, 如 Blu-ray、高清电视和游戏机

目前使用最广泛的 profile, 由其是 HD 分辨率电视应用 (如 Blu-ray / AVCHD 光盘储存、游戏机等电视多媒体播放器、HDTV DVB 广播服务)

现今的行动播放设备都可以流畅播放用此 profile 的 SD 分辨率影片, 中阶等级可以上 720p 分辨率, 高阶甚至可上 FullHD (软解可能会有点吃力, 硬解完全没问题)

High 10 Profile

支持更高位深和更精确的色彩取样, 主要用于专业领域

超越目前主流的消费型产品能力, 此 profile 建立在 High Profile 之上, 多了支持 10 bit 的精度, 色彩更精准。

以影片压制而言, 将 High Profile (8 bit) 影片重新编码输出为 H.264 High 10 Profile , 虽然色彩精度不会变, 但至少压缩率比输出 High Profile (8 bit) 还要高。

High 4:2:2 Profile

针对专业领域应用, 此 profile 建立在 High 10 Profile 之上, 多了支持 4:2:2 色彩取样, 比特深度达 10 bit

High 4:4:4 Predictive Profile

支持最高的色彩精度和无损压缩, 适合专业需求

此 profile 建立在 High 4:2:2 Profile 之上, 多了支持 4:4:4 色彩取样, 比特深度达 14 bit, 并且支持高效率无损重新编码, 且每张画面编码为三个独立的色彩平面

H.264 Frame Types

影片是由许多连续的 Frames 所组成, 但并不是所有 Frames 都是完整的画面, 那些 Frames 需要参考其他 Frames 才能解码出一张完整的画面。

H.264 使用三种不同类型的帧, 以减少数据量和提高压缩效率:

I-frame

独立完整的帧, 可直接解码, 不依赖其他帧

不需要参考其他 Frames, 是一张完整的画面。

IDR frame 为真正的 关键帧 (keyframes), P-frame & B-frame 不会越过 IDR frame 去参考其他 Frames, 所以可以随意跳转到任意 IDR frame 开始播放/解码, 而不会发生问题。

P-frame

记录相对于前一帧的差异, 只保存变化部分, 提高压缩效率

只记录了与之前的 Frames 相异的区块, 最多可以参考 16 张 之前的 Frames

播放 / 解码时需要参用到之前的 Frames 的部分资料, 才能解码出完整画面

在 x264 中, 你不能控制 P-frame 数量, 但你可以控制一个 P-frame 所能参考的 Frame 数量, 也就是 Reference frame (ref) 的数值

B-frame

利用前后两帧的信息记录差异部分, 具有最高的压缩率, 但增加了解码的复杂度

只记录了与前一张与后一张的 Frames 相异的区块, 压缩率高(由其是在低动态/低变化的影片), 播放/解码时需要用到前后两张的 Frames 的部分资料, 才能解码出完整画面

例子

(登入后即可检视图片)
从此图你可以发见 B-Frame 有用到前一张与后一张 Frame 的资料

播放 Farme 的顺序是依照 Frame 的时间点, 但解码顺序则不一定, 当 B-Frame 有用到后一张 Frame 的资料时, 就必须预先解码后一张 Frame

以上图为例
解码(处理)顺序: 1-2-4-3
显示(播放)顺序: 1-2-3-4

由于 P-/B-frame 不是完整的画面, 解码时必须参考其他 Frames, 所以你不能随意跳转到 P-/B-frame 上播放/解码

也就是说你如果播放 MPEG 视频格式, 当你跳播放时间点时, 正常而言, 并不会跳到你所选的时间点上, 而是最近的 IDR / I-frame


就压缩率而言…
由于 P-/B-frame 并不是完整的画面, 所以占用的空间较少, 提高这类 Frame 使用量可以有效提升压缩率, 但对画质几乎不会降低, 这代表可以使用较少的 bitrate (比特率) 达到维持一定画质

由以上得知, 在 bitrate 充足的情况下, 则不需要使用较多 B-frame、Reference frame (ref), 多少 bitrate 为充足依影片内容为定, 高动态影片需要较多 bitrate, 低动则较少

至于使用时机…
提高 B-frame/ref 使用量可以降低 bitrate 的需求, 使用较少 bitrate 达到目标品质。低动态的影片可以使用较多的 B-frame, 高动态或是纯静态则是 P-frame 效果较好

对于相容性与硬件负担…
提高 B-frame/ref 使用量的副作用是降相容性以及提高硬件负担, 请先保证相容性再来追求压缩率。

而 ref 的副作用要比 B-frame 强, 例如 ref=16 这代表解码一个 P-frame 必须要连跳回 1~16 张之前的 Frames 取用资料。

x264 参数设置

Max B-frame (bframes)

控制 B-frame 的最大数量, 用于提升压缩率。

当设置 B-frame 时, 重复部分比较多/变化较少的 Frames 会被编码为 B-frame

Reference frame (ref)

指定 P-frame 的参考帧 (Frames) 数量。适度提高该值可优化压缩效果, 但会增加硬件解码负担

推荐设置

GOP 长度

指定关键帧 (IDR frame) 的间隔, 以便在跳转播放时保持解码的流畅性。

一个 keyframe (IDR frame) 到下一个 keyframe 的范围。

所以将 GOP 设为无限大虽然可以大幅增加压缩率, 但这样就不能随意跳转到其他时间点播放/解码。

建议维持 default 即可

Profile 和 Level

决定视频的压缩比和硬件性能需求, Profile 越高代表更高的压缩率和更复杂的编码, 但要求设备具有更高的解码性能

interlaced (隔行扫描)

支持编码输出 interlaced (隔行扫描) 的视频

x264 预设 (Preset)

x264 提供了多种预设选项 (Preset), 从 ultrafast 到 placebo, 用于控制编码速度和压缩效率的平衡。一般建议选择一个合适的预设以在编码效率和文件大小之间取得平衡。

速度越慢则会得到更好的压缩编码效率 (画质-比特率比 或 画质-视频大小比)。也就是说, 若你设置一个目标比特率或是视频大小, 则越慢的 Preset 将会得到更好的输出品质。而对于设置一个恒定品质 (CRF) 或是恒定量化值 (QP), 你可以透过选择更慢的 Preset 来简单的节省比特率 (也就是得到更小的视频大小)。

一般而言是使用你所能忍受的最慢 Preset。目前 Presets 依速度递减排序是

该默认 Preset 是 medium, 忽略 placebo 因为它会比 veryslow 浪费更多时间而且效果差异太小。

而越慢的 Preset 其 Reference frame (ref) 值也越高, 例如 veryslow preset 的 ref 为 16。由于通常不需这么高的 ref, 你可以透过指定一个 Level 来限制 ref, 或是手动指定一个合理的 ref 值 (1 ~ 6)

x264 微调 (Tune)

Tune 参数则是针对特定内容类型 (如电影、动画、低延迟等) 优化的设置, 以改善特定应用的压缩效果。

压缩效果 内容类型
film (电影) 胶片电影、真人类型
animation (动画) 例如卡通/日本动画
grain (胶片颗粒) 颗粒感很重的影片。需要保留大量的 grain 时用
stillimage (静止影像) 例如幻灯片效果的影片。静态图像编码时使用
PSNR 优化 PSNR 值。 Wiki 为提高 psnr 做了优化的参数
SSIM 优化 SSIM 值。 Wiki 为提高 ssim 做了优化的参数
Fast Decode (快速解码) 用于低性能播放设备。可以快速解码的参数 (※ 压缩率极低)
zerolatency (零延迟) 处里时间低延迟。主要用于直播等。用在需要非常低的延迟的情况下, 比如电视电话会议的编码。(※ 压缩率极低)

参考实例

以下示例演示了如何应用基本选项来输出压缩高效的 H.264 视频文件

常规压缩 (适用于一般影片)

此命令使用 slow 预设, 以获得较高压缩比, CRF 设置为 20, 这将保持高画质


动画影片 (适用于卡通或动画类型)

--tune animation 调整了编码参数, 以确保细节和动态画面效果适合动画


低延迟设置 (适用于直播或会议场景)

--tune zerolatency 适用于需要快速解码的实时场景

H.264 Level

H.264 的 Level 和 MaxDpbMbs 直接表示了播放设备的解码性能要求。Level 值越高, 设备的解码性能要求越高, 输出影片的压缩率也越高。

MaxDpbMbs 对应的 Level

Wikipedia - Decoded picture buffering

Level MaxDpbMbs
1 396
1b 396
1.1 900
1.2 2,376
1.3 2,376
2 2,376
2.1 4,752
2.2 8,100
3 8,100
3.1 18,000
3.2 20,480
4 32,768
4.1 32,768
4.2 34,816
5 110,400
5.1 184,320
5.2 184,320
6 696,320
6.1 696,320
6.2 696,320

关系方程式

强制指定 Level (限制 MaxDpbMbs)

$$ \text{ref} = \min\left(\text{Floor}\left(\frac{\text{MaxDpbMbs}}{\text{PicWidthInMbs} \times \text{FrameHeightInMbs}} \right), 16\right) $$

  1. Floor(x): 向下取整数, 小数点直接舍去。 ex. Floor(1.9) = 1
  2. Min(x, y): 取比较小的数值。 ex. Min(2, 5) = 2

强制指定 ref

$$ \text{MaxDpbMbs} = \text{PicWidthInMbs} \times \text{FrameHeightInMbs} \times \text{ref} $$

计算 PicWidthInMbs 和 FrameHeightInMbs (小数点向上取整)

$$ \text{PicWidthInMbs} = \frac{\text{Width}}{16} $$

$$ \text{FrameHeightInMbs} = \frac{\text{Height}}{16} $$

示例

输出设置

计算 MaxDpbMbs:

$$ \text{MaxDpbMbs} = 80 \times 45 \times 4 = 14400 $$

对照表得出 Level = 3.1


输出设置

计算 ref

$$ \text{ref} = \min\left(\text{Floor}\left(\frac{18000}{80 \times 45}\right), 16\right) = \min(5, 16) = 5 $$

输出 H.264 的 ref 可能为 4 或 5

同时强制指定 ref 与 Level

ref 设置值不能大于 5 (强制指定 ref 不能超过 Level 的限制)

x264 比特率控制

x264 提供多种输出品质和比特率控制方式, 主要包括 Constant Rate Factor (CRF) 和 2-Pass Bitrate。速率控制是指决定多少比特将被用于每帧的方法。这将决定视频大小且品质如何分布。而 CRF 的比特率分配效果是最佳的, 若无控制输出大小的需求则使用 CRF 即可。

Constant Quantizer (QP)

设置 x264 以恒定量化值 (Constant Quantizer) 模式来编码视频。此方法可以让每帧获得相同品质 (设置值)。

设置值范围: 0 - 69, 0 为最无损, 默认值为 23。比较低的数值会得到比较高的品质, 合理的范围 21 - 28。

Constant Ratefactor (CRF)

此方法允许编码器自动分配比特速率来试着达到一定输出品质。让每帧得到它需要的比特率来保持所需的品质等级。CRF 会得到最佳的比特速率分配结果, 缺点是你不能直接指定一个目标比特率或是视频大小。

设置值范围为 0 - 51.0, 0 为最高品质, 默认值为 23。比较低的数值会得到比较高的品质, 合理的范围 18 - 28。考虑 18 为视觉无损 (或接近), 所以它看起来应该与输入相同 (或接近) 但它技术上不是无损。

Bitrate

自订 Bitrate 控制输出 Size, 直接编码输出视频。由于没有先扫描过一次, x264 无法得知影片各时间点的复杂程度。所以 x264 只能在编码中不断猜后之后的复杂程度, 这样将不能精准依各时间点的复杂程度等比例分配比特率, 因为如果之前分配了过多流量, 那么之后就必下修流量来使输出比特率平均值等于用户设置值

Bitrate, 2-Pass

此方法让编码器 1st-Pass 将会得知影片各个帧的复杂程度, 2nd-Pass 时依照输入视频各个帧的复杂程度等比例分配比特数输出, 并且最终平均比特速率会等于设置值。2-Pass 比特速率分配结果会接近 CRF, 缺点是耗费大量时间

1st-Pass CRF + 2-Pass Bitrate

此方法让编码器在 1st-Pass 时将会得知影片各个帧所需要的比特数, 2nd-Pass 时依照各个帧所需要的比特数等比例分配使最终比特速率总平均值会等于设置值。2-Pass 比特速率分配结果会接近 CRF, 缺点是耗费大量时间

x264 设置优先级

设置优先级顺序

当参数冲突时, 后者会取代前者或是影响前者

preset slower 的参数为

当我设置

等同于

输出 H.264 的 Reference frame (ref) 为 4


当我设置

输出 H.264 的 Reference frame (ref) 为 5

基本用法

基本语法

输入格式支持

输出文件格式

Piping 使用方法

64bit 的 x264

如果用了 64 位的 Windows, 就可以用 64 位的 x264。64 位的 x264 大约能比 32 位的 x264 快上 10% 左右, 能节省的时间还是比较可观的。但是用 AviSynth 输入时, 64 位的 x264 只接受 64 位的 AviSynth 输入, 32 位的 x264 只接受 32 位的 AviSynth。

虽然现在有 64 位的 AviSynth 和不少常用的滤镜, 但是大多数人还是愿意用 32 位的 AviSynth。那么如何用让 64位的 x264 配合 32 位的 AviSynth 呢?

方法是用 pipe。用命令行工具 (如 ffmpeg、mencoder 或 avs2yuv) 打开 avs, 让输出的 raw yuv 画面直接输入给 x264, 期间不产生中间文件。这个操作也是在命令行里实现的。

使用 ffmpeg 输入

先下载 ffmpeg 的 Windows 编译版, 可以用 static link 版本。和 x264 一样, ffmpeg 放在任何目录里都能运行, 假设和 x264、要进行编码的 input.avs 放在一个目录里

先用 ffmpeg 打开 input.avs, 并不指定输出的文件, 而是以 - 代替输出的文件。后面写 |, 再写 x264, x264 的选项和输出文件写法不变, 但是输入文件写 -

使用 mencoder 输入 (未测试)

mencoder 有很多有价值的滤镜, 用起来也很方便。libx264 可以编译进 mencoder 本身, 和单独的 x264 效果一样。mencoder 也可以打开 avs 文件, pipe 给 64 位的 x264。mplayer-ww 的命令行版里就带有 mencoder

同样假设 mencoder、x264 和要编码的 input.avs (1280x720) 在一个目录里

使用 avs2yuv 输入

avs2yuv 本来是为了给 linux 上 wine 来用的, 因为 AviSynth 是运行在 Windows 的, 在 linux 里必须 wine avs2yuv 来打开 avs, 再 pipe 给 x264。当然也可以用来 pipe 给 64 位的 x264

同样假设 avs2yuv、x264 和要编码的 input.avs 在一个目录里

avs2yuv 的输出格式默认是 yuv4mpeg, x264 用 y4m 格式解码即可从中读取分辨率, 所以无须再用 --input-res 指定分辨率

以上介绍了 3 种方法, 个人比较倾向于用 ffmpeg。2pass 的编码也是像上面所讲的方法一样


原文

Wikipedia - H.264/MPEG-4 AVC
VideoLAN - x264
Wikipedia - x264
X264使用介绍 关于pipe
x264 - 高品质 H.264 编码器