mpeg1/2 量化过程

场景: ffmpeg -i b3e.mpeg -dct int -idct int -threads 1 -y yy.mpeg 

(源码需要稍微修改下, 见杂项)

1. 编解码流程 

先回顾一下我们处于哪个阶段。

pthread_slice.c:worker--> encode_thread-->

 ff_set_qscale(5);

 ff_mpeg1_encode_slice_header:
   SLICE_MIN_START_CODE qscale 5bits
 encode_mb_hq-->encode_mb-->encode_mb_internal-->
    dct_quantize=ff_dct_quantize_c-->
       ff_jpeg_fdct_islow_8 //DCT 
       bias_qmat //量化
    ff_mpeg1_encode_mb-->mpeg1_encode_mb_internal-->mpeg1_encode_block -->encode_dc,vlc//熵编码

avcodec_decode_video2-->mpeg_decode_frame-->decode_chunks-->mpeg_decode_slice-->
 mpeg_decode_mb-->mpeg1_decode_block_intra//熵解码
 ff_MPV_decode_mb-->put_dct-->
  dct_unquantize(block, i, qscale)=dct_unquantize_mpeg1_intra_c//反量化
  ff_idct_put(dest, block)=ff_j_rev_dct//反DCT

2. 量化过程
DCT把一部分计算转移到量化,以减少累积误差,他们是紧耦合的!只说量化而不涉及DCT是不对的!体现在
ff_MPV_encode_init-->ff_convert_matrix(q = s->q_intra_matrix, m = ff_mpeg1_default_intra_matrix)
  根据fdct做不同的初始化,其中
uint16_t ff_mpeg1_default_intra_matrix={
        8, 16, 19, 22, 26, 27, 29, 34,
        16, 16, 22, 24, 27, 29, 34, 37,
        19, 22, 26, 27, 29, 34, 34, 38,
        22, 22, 26, 27, 29, 34, 37, 40,
        22, 26, 27, 29, 32, 35, 40, 48,
        26, 27, 29, 32, 35, 40, 48, 58,
        26, 27, 29, 34, 38, 46, 56, 69,
        27, 29, 35, 38, 46, 56, 69, 83
}; 这个是加权矩阵,左上角值最小,表示权重越大。

 q[scale][i] = (1 << 21)/(scale * m[i]);
 q_intra_matrix 等矩阵按照6.2.3.2 Quant matrix
extension语法规定ff_write_quant_matrix到比特流里面(可选, ffmpeg没写),供解码端使用。
 
2.1 ff_dct_quantize_c 量化每一个系数b_大致简化_为:
  c = b /(scale * m)

解码端,mpeg1_decode_sequence如果流里面有就load_matrix(m=s->intra_matrix)否则
取m = ff_mpeg1_default_intra_matrix。
dct_unquantize_mpeg1_intra/inter_c:
 b = c * scale * m/8
 b = (2*c+1)*scale*m/16

跟 7.4.2.3 Reconstruction formulae 不完全一样。

问题:为什么解码端多了一个除以8的因子,而编码端没有?
答案:因为标准13818-2 Annex A规定fdct输出的系数用12比特表示9比特系数值。
这个问题折磨我两天,各种胡猜,见后面的杂项。什么左移右移 CONST_BITS,
PASS1_BITS, OUT_BITS啊,夹杂在一起,就迷糊了。

2.2 clip_coeffs 对应到 7.4.3 Saturation, 把值裁剪到[min_qcoeff, max_qcoeff] = [-2047, 2047]范围内。
encode时没有做 7.4.4 Mismatch control,只是在mpeg2 decode才做的。

2.3 量化之后其实还有一个ff_block_permute:
(gdb) x /64ob scantable = ff_zigzag_direct
0x11f79a0 0       01      010     020     011     02      03      012
0x11f79a8 021     030     040     031     022     013     04      05
0x11f79b0       014     023     032     041     050     060     051     042
0x11f79b8       033     024     015     06      07      016     025     034
0x11f79c0       043     052     061     070     071     062     053     044
0x11f79c8       035     026     017     027     036     045     054     063
0x11f79d0       072     073     064     055     046     037     047     056
0x11f79d8       065     074     075     066     057     067     076     077

(gdb) p s->idsp.perm_type                         
$5 = FF_IDCT_PERM_LIBMPEG2
(gdb) x /64ob s->idsp.idct_permutation            
0x1d99f70:      0       04      01      05      02      06      03      07
0x1d99f78:      010     014     011     015     012     016     013     017
0x1d99f80:      020     024     021     025     022     026     023     027
0x1d99f88:      030     034     031     035     032     036     033     037
0x1d99f90:      040     044     041     045     042     046     043     047
0x1d99f98:      050     054     051     055     052     056     053     057
0x1d99fa0:      060     064     061     065     062     066     063     067
0x1d99fa8:      070     074     071     075     072     076     073     077
只是列重排: [0,1,2,3,4,5,6,7]-->[0,4,1,5,2,6,3,7],我检查了-idct simple是不需要重排的。
重排存在的原因是编码的各个模块需要的数据格式和顺序不同。比如mmx输入的顺序和输出到比特流的顺序不同。

注意到老版block_permute(block);是放在量化前面的,对64个值重排;新版放在后面,只对last_non_zero个重排,
并且last_non_zero通常是0,效率自然增加了,赞一个!

TODO

====

1. 默认是 dct_quantize_ssse3(x86/mpegvideoenc_template.c),以后有空看看mmx,sse技术。

2. fixed-point math


杂项
====
技巧:
找不到这个函数哪里定义的,到gdb里面b 它, 就会出现jfdctfst.c, line 216。
到某个地方想查看函数指针什么的指向哪里,而step进不去时,disas看即可。

作为对比,ff_jpeg_fdct_islow_8,-dct 参数分别为fastint和int。
我原先为怎么指定quantize发愁呢,结果发现只需指定-dct就行了,ff_dct_quantize_c总是和ff_fdct_ifast/ff_jpeg_fdct_islow_8绑定的。
遗憾的是反量化没得参数可设定,-idct int
或simple都没有用,s->dct_unquantize_mpeg1_intra总是被ff_MPV_common_init_x86()重置,那把它放空好了。
同理也把ff_idctdsp_init_x86放空。

<-------------
#define QMAT_SHIFT 21
#define QUANT_BIAS_SHIFT 8
 // (a + x * 3 / 8) / x
s->intra_quant_bias = 3 << (QUANT_BIAS_SHIFT - 3) = 96;
s->inter_quant_bias = 0;
qmat = q_intra_matrix[qscale] = (int)((UINT64_C(1) << QMAT_SHIFT) / (qscale * ff_mpeg1_default_intra_matrixj))
bias= s->intra_quant_bias<<(QMAT_SHIFT - QUANT_BIAS_SHIFT) = 96*8*1024 = 786432
threshold1= (1<<QMAT_SHIFT) - bias - 1 = 2*1024*1024 - 786433 = 1310719
threshold2= (threshold1<<1) = 2621438

level = block[j] * qmat[j];
if( level+threshold1 > threshold2)
 block[j]= (bias + level)>>QMAT_SHIFT;

 [96<<(QMAT_SHIFT - QUANT_BIAS_SHIFT) + b * (1<<QMAT_SHIFT)/(scale*m) ]>>QMAT_SHIFT
---->
因为编码端
BITS_IN_JSAMPLE + PASS1_BITS + 3 = 8+4+3 = 15
CONST_BITS + OUT_SHIFT = 13+4 = 17

ff_fdct_ifast里面已经DESCALE了,符合标准。
而解码端idct期望输入系数已经乘以8。
我猜可能是idct需要比较小的数,比如1*5*19/8 =

11。那dct呢?它的输入是最大是Y分量8比特不超过255。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值