分页: 9 / 21

Re: x264 10bit编码推广讨论

发表于 : 2011-08-06 9:57
histamine
akiduki 写了:1. 你看清楚,我说的是8->16没有问题。
2. 8->10的转换确实有问题,但和dither_plane没有关系。请你再读一遍dither_plane里面你应用的那句注释。
3. 我不知道avs变相输出16-bit给x264会是什么样的路径,看上去会走dither_plane吧。avs输出16-bit的那个trick我没仔细研究过。再者,16-bit的limited range YUV是什么样的nominal peak可没标准定义。所以这里本身就是个问号。
4. madshi用的是full range RGB,不是YUV,别看错了。
5. madshi提出的banding问题,本身的问题提出就是错的。而且在他推崇的直接左移两位的方法(也是MSDN的方法)中也存在,你自己算下就知道了。
这不奇怪,原本8-bit的unit(1) value差,转换成>8bit后差值应该大于1,而大于1并不等于出现了gradient的增加(banding)。8bit原有的dynamic,提高bitdepth后应该保持(不可能增加,这样就违背信息论了。dithering另当别论。)才对。
就像你考试得了10分中的9分,我得了8.5分;换成百分制后你是90我是85,那你能说换了百分制后我和你之间的分差增大了么?
第一点我保留自己的观点,持怀疑态度。
第二点我认同,我说的是“16bit输入x264时的16bit->10bit的dither”和“8bit输入时发生在x264内部的8bit->16bit->10bit转换,无涉及dither路径”,这点上我们达成一致看法
第三点最终输出的是10bit,BT.709标准里定义了10bit的nominal peak,至少这是可以肯定的
第四点和第五点认同,再次达成一致看法。

于是现在需要关注的是如何修改libswscale和x264的depth filter,做正确的8bit->10bit转换以及16bit->10bit的dither?

Update:
十分制转换到百分制的例子,衡量两个情况下差距时应该将差值标准化后才能比较,比如将十分制下差距0.5除以10和百分制下5除以100比较,得出结果是差距是相同的。

对于madshi举的例子:
8bit full-range RGB data:
60, 61, 62, 63, 64, 65, 66, 67

10bit full-range RGB data, upscaled with x264:
240, 244, 248, 252, 257, 261, 265, 269
原先8bit下相邻数字间相差均为1
用x264目前的算法转换到10bit后,(257-252=)5,而(269-265)=(265-261)=(261-257)=(252-248)=(248-244)=(244-240)=4?!

如果按照Y = X*(2^8+1)或者Y = X*2^8将8bit数值X转换到16bit数值Y

对于8bit数值序列60, 61, 62, 63, 64, 65, 66, 67

按照Y = X*(2^8+1)转换后为
15420,15677,15934,16191,16448,16705,16962,17219
相邻数值相差为(2^8+1)

按照Y = X*2^8转换后为
15360,15616,15872,16128,16384,16640,16896,17152
相邻数值相差2^8

唯一的区别是
按照Y = X*(2^8+1)转换后,16bit数值Y范围是0 ~ (2^16-1)
按照Y = X*2^8转换后,16bit数值Y范围成了0 ~ (2^16-2^8)

那么将差值标准化,(2^8+1)/(2^16-1)等于2^8/(2^16-2^8)等于1/(2^8-1),差距相等

然后对于两种方法得到的16bit数值序列同时使用右移6位转换到10bit
左移8位加原数值,然后再右移6位:
240,244,248,252,257,261,265,269
左移8位,然后再右移6位(等同于左移2位):
240,244,248,252,256,260,264,268
前者产生了banding,后者无banding,是我理解错了吗,还是大大您错了? {:cat_18}

如果我没算错的话,使用x264目前的dither算法将
15420,15677,15934,16191,16448,16705,16962,17219
转换到10bit,结果是
241,245,249,253,257,261,265,269
无banding

对于limited range按BT.709标准
8bit 16-235 16-240
10bit 64-940 64-960

(940-64)/(235-16)=(960-64)/(240-16)=2^2
所以我认为按照BT.709标准limited range YUV 8bit转换到limited range YUV 10bit应该直接左移2位

如果我没算错的话,对于目前x264里面的dither算法,如果将235*(2^8+1)转换到10bit,结果是943
如果将235*2^8转换到10bit,结果是940或939,会有误差

如果将errors[x] = err = src[x*pitch] - (dst[x*pitch] << lshift) - (dst[x*pitch] >> rshift);
改成errors[x] = err = src[x*pitch] - (dst[x*pitch] << lshift);
再将235*2^8转换到10bit,结果是940

有错误,请仔细阅读后指出

Re: x264 10bit编码推广讨论

发表于 : 2011-08-06 18:11
06_taro
摘自R-REC-BT.601-7-201103-I!!PDF-E.pdf的Annex 1 - Encoding parameters for members of the family中Table-3/Table-4内9. Code-word usage
When 8-bit words are treated in 10-bit system, two LSBs of zeros are to be appended
to the 8-bit words.
摘自R-REC-BT.709-5-200204-I!!PDF-E.pdf的6 Digital representation中注释(3)
For 1125/60/2:1 – For 10-bit coding two LSBs are added to the 8-bit code words.

Re: x264 10bit编码推广讨论

发表于 : 2011-08-06 18:44
histamine
也就是说按照BT.601和BT.709正确的做法就是左移2位?

dst[k] = ((src[k] << 8) + src[k]) >> shift;
应该改成
dst[k] = ( src[k] << 8 ) >> shift;或者dst[k] = src[k] << 2;

如果是这样的话,我觉得dither算法里面
errors[x] = err = src[x*pitch] - (dst[x*pitch] << lshift) - (dst[x*pitch] >> rshift);
应该改成
errors[x] = err = src[x*pitch] - (dst[x*pitch] << lshift);
理由我上面说了,前提是我没算错的话 {:cat_2}

Re: x264 10bit编码推广讨论

发表于 : 2011-08-06 21:35
06_taro
我认为low bit depth->high bit depth就是应该简单地按位左移,即使是以后实现Hi444P里的14bit也不例外。dither应该在high bit depth的源输入而输出要求是low bit depth时做,或者至少给个参数去控制是否做。low->high从编码是尽量保留源信息的角度上看没必要也不应该转到16再降,除非在内部有16bit的为了提高编码质量的运算

Re: x264 10bit编码推广讨论

发表于 : 2011-08-06 21:42
histamine
如果是gradfun3/dfttest处理就有保留16bit输出的必要,这时遇到一个问题16bit应该如何dither到10bit
也就是说我们利用dither系列工具输出伪16bit交给x264编码,应该采用何种dither方式?
我觉得这和我们输出的16bit数据的定义有关,16bit数据并不代表数值范围一定是0 ~ (2^16-1),就像我们可以不使用100分制,而使用偏门的90分制

如果我们假定“x264里左移8位再加上原数值,将8bit转换到16bit”是正确的,正如aki巨巨说的“1. 你看清楚,我说的是8->16没有问题。”,那么按照一般的dither方法进行16bit到10bit的转换,最初8bit数值235最终结果是10bit下943,不符合BT.709标准,我们需要寻找另一种16bit->10bit的dither方法。

对于一般的8bit输出确实没有必要转换到16bit再降到10bit,应该直接将8bit数据转换到10bit数据,这点我绝对认同,我完全认同taro巨巨的看法
所以裸压的话,应该修改下x264代码,将输入的8bit数据左移2位转换到10bit数据
这里注意“将8bit数据左移8位转换到16bit,然后再右移6位转换到10bit”的方法和“将8bit数据左移2位转换到10bit”的方法是等价的

在关于madshi提出有关banding的问题上,aki巨巨说“原本8-bit的unit(1) value差,转换成>8bit后差值应该大于1,而大于1并不等于出现了gradient的增加(banding)”,我觉得aki巨巨并没有真正理解madshi想说的,首先aki巨巨说的这句话是对的,但是madshi想表达的是“The gradient isn't smooth”,也就是说他是指(257-252)=5,而(269-265)=(265-261)=(261-257)=(252-248)=(248-244)=(244-240)=4,所以产生了banding。


我承认自己的表达能力不是很好,有任何怀疑或者不理解的地方,欢迎讨论。

Re: x264 10bit编码推广讨论

发表于 : 2011-08-06 23:19
akiduki
06_taro 写了: 摘自R-REC-BT.709-5-200204-I!!PDF-E.pdf的6 Digital representation中注释(3)
For 1125/60/2:1 – For 10-bit coding two LSBs are added to the 8-bit code words.
这句话好歧义啊,到底是add 8-bit的低2位到shift了2位的10-bit值上成为最终值呢,还是直接shift 2位?
601的说法看上去像是很明确的等同于shift 2位。
06_taro 写了:我认为low bit depth->high bit depth就是应该简单地按位左移,即使是以后实现Hi444P里的14bit也不例外。dither应该在high bit depth的源输入而输出要求是low bit depth时做,或者至少给个参数去控制是否做。low->high从编码是尽量保留源信息的角度上看没必要也不应该转到16再降,除非在内部有16bit的为了提高编码质量的运算
只能跟着标准走,标准怎么说我们就只能怎么做-_-
我同意low->high不走16bit这个观点。不过x264走了16么?看代码似乎直接就变成10了啊。
如果我们假定“x264里左移8位再加上原数值,将8bit转换到16bit”是正确的,正如aki巨巨说的“1. 你看清楚,我说的是8->16没有问题。”,那么按照一般的dither方法进行16bit到10bit的转换,最初8bit数值235最终结果是10bit下943,不符合BT.709标准,我们需要寻找另一种16bit->10bit的dither方法。
我自始至终都怀疑从dither_plane的这个函数实际使用时没有调用,这个函数是为了降回输入bitdepth用的(注释上也说了)。如果直接输出10bit,用的就是我早先贴的那句。
在关于madshi提出有关banding的问题上,aki巨巨说“原本8-bit的unit(1) value差,转换成>8bit后差值应该大于1,而大于1并不等于出现了gradient的增加(banding)”,我觉得aki巨巨并没有真正理解madshi想说的,首先aki巨巨说的这句话是对的,但是madshi想表达的是“The gradient isn't smooth”,也就是说他是指(257-252)=5,而(269-265)=(265-261)=(261-257)=(252-248)=(248-244)=(244-240)=4,所以产生了banding。
嗯,这个地方我没弄清楚,确实是不smooth。

我的核心是这里没有8->16,然后再用dither_plane down回10这两个函数分别作用的过程。而直接是一步解决的[(左移8+低位8)>>6],所以纠结于怎么写个dither把16的down回正确range的10没意义,直接改掉scale里面的那段就是了(a<<(BITDEPTH-8))。在前面的帖子里你自己也比较了这两种方法,说了x264的方法conversion后出现gradient不smooth的情况,这就是exactly x264输入8bit后做的事啊-_-然后怎么就又冒出dither来了呢。

Re: x264 10bit编码推广讨论

发表于 : 2011-08-06 23:23
histamine
akiduki 写了:我自始至终都怀疑从dither_plane的这个函数实际使用时没有调用,这个函数是为了降回输入bitdepth用的(注释上也说了)。如果直接输出10bit,用的就是我早先贴的那句。
但是x264是支持16bit输入的,这时16bit->10bit用的并不是
dst[k] = ((src[k] << 8) + src[k]) >> shift;
这句的吧

如果没有调用到dither_plane函数,那么我们利用dither系列工具输出伪16bit时x264内部走了怎么样的路径?
注意这时候我们已经指定了--input-depth 16
我们能保证这个路径是正确的吗?
akiduki 写了:在前面的帖子里你自己也比较了这两种方法,说了x264的方法conversion后出现gradient不smooth的情况,这就是exactly x264输入8bit后做的事啊-_-然后怎么就又冒出dither来了呢。
我说的dither并不发生在x264输入8bit的情况下,而是发生在输入16bit的情况下,这个时候我们输入的16bit是如何得到的,x264并不知道

如果是Dither_convert_8_to_16().Dither_convey_yuv4xxp16_on_yvxx()输出的话,实质等同于左移8位,和x264注视里写的

代码: 全选

8-bit is converted to 16-bit through left shifting the orginal value with 8 and then adding the original value to that
并不一样,也就是说我们不该用那个dither_plane函数进行16bit->10bit转换,因为

代码: 全选

It has been written in such a way so that if the source has been upconverted using the same algorithm as used in scale_image, dithering down to the source bit depth again is lossless.
我自己也算过了,如果采用这个dither_plane函数,16bit->10bit转换会有一点点误差(和8bit源直接左移2位得到10bit数据相比),不过我怀疑肉眼无法分辨

关于x264内部的dither,DS在这个帖子里说"Patches welcome to try another dither method, or find the problem in the existing one. The existing one is just an implementation of error diffusion; perhaps ordered dither works better?"
http://forum.doom9.org/showthread.php?p ... ost1518071

之前我也说了
histamine 写了:第二点我认同,我说的是“16bit输入x264时的16bit->10bit的dither”和“8bit输入时发生在x264内部的8bit->16bit->10bit转换,无涉及dither路径”
不知道我是表达有误还是怎么的,又让巨巨误会了

C语言我不是很熟悉,在depth.c里面定义了这个depth filter的get_frame接口

代码: 全选

static int get_frame( hnd_t handle, cli_pic_t *output, int frame )
{
    depth_hnd_t *h = handle;

    if( h->prev_filter.get_frame( h->prev_hnd, output, frame ) )
        return -1;

    if( h->bit_depth < 16 && output->img.csp & X264_CSP_HIGH_DEPTH )
    {
        dither_image( &h->buffer.img, &output->img, h->error_buf );
        output->img = h->buffer.img;
    }
    else if( h->bit_depth > 8 && !(output->img.csp & X264_CSP_HIGH_DEPTH) )
    {
        scale_image( &h->buffer.img, &output->img );
        output->img = h->buffer.img;
    }
    return 0;
}
继续补充,在x264.c中有一个init_vid_filters函数
其中一段是

代码: 全选

    char args[20];
    sprintf( args, "bit_depth=%d", x264_bit_depth );

    if( x264_init_vid_filter( "depth", handle, &filter, info, param, args ) )
        return -1;
在x264.h里面有一行

代码: 全选

extern const int x264_bit_depth;
在common.c中有一行

代码: 全选

const int x264_bit_depth = BIT_DEPTH;
在common.h中有一行

代码: 全选

#define BIT_DEPTH X264_BIT_DEPTH
睡觉去,有问题8小时后继续讨论,明天还得给字幕组压片

Re: x264 10bit编码推广讨论

发表于 : 2011-08-07 0:15
06_taro
确实如果是高bit下做了dfttest/gradfun3等处理就有价值了。

16bit内确实不是全部可用的,和8bit时保留0/255作为同步基准值一样,10bit保留了0-3/1020-1023做同步,当然和现在这东西没啥关系。在TV Range范围内,16-235/240到64-940/960的映射应该也是不存在dither需要,这个上面已经共识了。如果是到16bit再降下来,实际上我认为主要问题也是因为range不同导致的dither时需要考虑的level clamping(doom9里D_S也意识到了这个horrific的事情-_,-),而在确定的range下譬如TV range下,应该只要求dither有一个确定的达到64-940/960,中心512的算法就行了,其实这就是现在x264里算法问题所在。而另一个madshi所说的banding问题,如果是直接<<2的话应该是不存在的,因为没有降低精度的操作,保持信息的位移过程没有系统损失。而在16->10里会由于量化精度下降而产生,其实精度下降的情况下(下降范围内的LSB值不为零时,譬如目前x264的8->16或者16bit下gradfun3/dfttest处理出来的结果)必然有对这些LSB进行导致质损的处理,不知道aki菊苣说的“madBanding”是不是这个意思,如果不是的话还请指正……至少这个downscale导致的banding是系统损失,dither能做的是将感官上损失降低,而不可能保留高精度下的数据,所以我觉得只有好坏之分没有正误之分,因此madshi这里说的banding我觉得其实不是什么问题。连8bit这种放到10bit下相差4的level step都能接受,10bit下仅仅相差1的不smooth的问题应该不算啥吧= =

另外在bit conversion上我还是认为,如果没有标准的话可以考虑具体做法的优劣,但在ITU-R标准里有讲到<<2的情况下还是应该按照标准来做,无论本身是否是最佳处理,至少如果解码时降到8bit的csp输出,或者显示器是8bit的所以显卡做了10->8(这个是不是显卡做的我也不知道= =),如果encoding阶段是将输入的10bit当作按照标准做出来的话,这个10->8的过程就可以同样按照标准做逆处理(至于是dithering、rounding还是直接ignoring另当别论)而不会产生色彩偏差,否则大家都乱套了。DVD时期那么多时代的眼泪很多就是不按照标准办事搞出来的。标准有问题可以研究新的标准,但在新标准出来之前还是应该按照原有标准做。

小白一个,围观学习……

Re: x264 10bit编码推广讨论

发表于 : 2011-08-07 0:17
06_taro
akiduki 写了: 这句话好歧义啊,到底是add 8-bit的低2位到shift了2位的10-bit值上成为最终值呢,还是直接shift 2位?
601的说法看上去像是很明确的等同于shift 2位。
是的,其实看709的时候我也纠结了半天到底是不是和601一样是指直接<<2,不过我觉得应该不会是在两位LSB上补什么其他数据吧= =

Re: x264 10bit编码推广讨论

发表于 : 2011-08-07 9:19
histamine
一个简单粗暴的方法,来验证16bit输入时x264有否调用dither_plane函数

也就是软件debug时最简单也最实用的printf大法

在depth.c里面添加
#include <stdio.h>
在get_frame函数中

148 if( h->bit_depth < 16 && output->img.csp & X264_CSP_HIGH_DEPTH )
149 {
150 printf("dithering!\n");//添加此句
151 dither_image( &h->buffer.img, &output->img, h->error_buf );
152 output->img = h->buffer.img;
153 }

{:cat_2}