histamine
帖子: 85
注册时间: 2010-09-23 20:07

Re: x264 10bit编码推广讨论

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

有错误,请仔细阅读后指出
头像
06_taro
核心会员
核心会员
帖子: 998
注册时间: 2010-09-22 18:32
来自: United Kingdom
联系: 网站

Re: x264 10bit编码推广讨论

摘自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.
つまんねー事聞くなよ!

I, personally, for me, believe (obviously sometimes) that my OS choice is right. That's me. I'm not telling you that you should believe it. Learn the facts, and the origins behind the facts, and make up your own damn mind. That's why you have one. (source)

Follow me: @06_taro

304——
为纪念伟大的宇宙史上最强压制304先生,联合国教科文组织决定,将每年的第304天,即平年的10月31日或者闰年的10月30日,定为世界304日。
histamine
帖子: 85
注册时间: 2010-09-23 20:07

Re: x264 10bit编码推广讨论

也就是说按照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}
头像
06_taro
核心会员
核心会员
帖子: 998
注册时间: 2010-09-22 18:32
来自: United Kingdom
联系: 网站

Re: x264 10bit编码推广讨论

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

I, personally, for me, believe (obviously sometimes) that my OS choice is right. That's me. I'm not telling you that you should believe it. Learn the facts, and the origins behind the facts, and make up your own damn mind. That's why you have one. (source)

Follow me: @06_taro

304——
为纪念伟大的宇宙史上最强压制304先生,联合国教科文组织决定,将每年的第304天,即平年的10月31日或者闰年的10月30日,定为世界304日。
histamine
帖子: 85
注册时间: 2010-09-23 20:07

Re: x264 10bit编码推广讨论

如果是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。


我承认自己的表达能力不是很好,有任何怀疑或者不理解的地方,欢迎讨论。
akiduki
核心会员
核心会员
帖子: 32
注册时间: 2010-09-19 22:32

Re: x264 10bit编码推广讨论

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来了呢。
histamine
帖子: 85
注册时间: 2010-09-23 20:07

Re: x264 10bit编码推广讨论

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小时后继续讨论,明天还得给字幕组压片
头像
06_taro
核心会员
核心会员
帖子: 998
注册时间: 2010-09-22 18:32
来自: United Kingdom
联系: 网站

Re: x264 10bit编码推广讨论

确实如果是高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时期那么多时代的眼泪很多就是不按照标准办事搞出来的。标准有问题可以研究新的标准,但在新标准出来之前还是应该按照原有标准做。

小白一个,围观学习……
上次由 06_taro 在 2011-08-07 0:20,总共编辑 1 次。
つまんねー事聞くなよ!

I, personally, for me, believe (obviously sometimes) that my OS choice is right. That's me. I'm not telling you that you should believe it. Learn the facts, and the origins behind the facts, and make up your own damn mind. That's why you have one. (source)

Follow me: @06_taro

304——
为纪念伟大的宇宙史上最强压制304先生,联合国教科文组织决定,将每年的第304天,即平年的10月31日或者闰年的10月30日,定为世界304日。
头像
06_taro
核心会员
核心会员
帖子: 998
注册时间: 2010-09-22 18:32
来自: United Kingdom
联系: 网站

Re: x264 10bit编码推广讨论

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

I, personally, for me, believe (obviously sometimes) that my OS choice is right. That's me. I'm not telling you that you should believe it. Learn the facts, and the origins behind the facts, and make up your own damn mind. That's why you have one. (source)

Follow me: @06_taro

304——
为纪念伟大的宇宙史上最强压制304先生,联合国教科文组织决定,将每年的第304天,即平年的10月31日或者闰年的10月30日,定为世界304日。
histamine
帖子: 85
注册时间: 2010-09-23 20:07

Re: x264 10bit编码推广讨论

一个简单粗暴的方法,来验证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}

回到 “视频编码器 / Video encoder discussion”