x264里的2pass指的是什么意思? x264源代码分析2.encode()

A:x264里的2pass指的是什么意思?另外stat是什么意思, 比如有个参数--stats <string>        Filename for 2 pass stats [/"%s/"]/n", defaults->rc.psz_stat_out );
stats在这是什么意思?


2pass是2次编码的意思,stats是统计文档的名称,记录了1pass中的信息.2次编码就相当于2次转换这么做虽然转换时间会漫长,但压出的片子会有更好的画质,画面细节更好,而且体积会更小

2-pass主要是针对非实时的视频编码(如文件)来说的,通俗的说就是需要二次编码,第一次编码是先对整个文件进行扫描,记录一些统计信息,第二次编码时根据前面记录的统计信息再进行编码,这样的好处是可以提高编码的质量。

A:那个达人能简单说说x264中 rc 部分 1pass 和 2pass的思路?

就此问题在 x264 开发邮件列表里问过。没有得到一个明确的结论。
我看代码的过程中,首先关注的是 1pass ,得到的一点经验大概可以这样描述:
首先 x264 中将 QP 通过一个确定的公式变换为 QScale 。其主要就是针对于 QS 作分析和控制/约束变化的
x264 的码率控制接口是以帧为单位的,而支持的宏块级变化只到宏块行
编码一个宏块行之前调用接口函数以得到欲使用的 QP 。
它预测某个 gomb (宏块组) 的耗费码流的大小,利用在漏桶模型上,以之权衡 QP 是否需要改变并如何进行改变。
预测的时候是使用两种预测求平均的方法,见 predict_row_size() 函数。
它的预测方程一个比较引起混淆的是它对历史数据有个衰减的过程。
而且,这些衰减概念,应用在不同地方所用的几个方程上。
它的 RC 核心函数是 rate_estimate_qscale() 。
其中一个 QS 的推导是一个需要解析的输入表达式字符串,也因此在内部实现了一个表达式解析器,也许会产生一点晦涩感。
一时就想到这些。

E.      然后进入x264_encoder_encode( h, &nal, &i_nal, pic )函数,该函数定义在/Enc/encoder.c中.

开始进入比较复杂的地方了.

这个函数前面有一段注释(如下):

****************************************************************************

* x264_encoder_encode:

* XXX: i_poc   : is the poc of the current given picture

*       i_frame : is the number of the frame being coded

* ex: type frame poc

*       I      0   2*0//poc是实际的帧的位置.

*       P      1   2*3//frame是编码的顺序.

*       B      2   2*1

*       B      3   2*2

*       P      4   2*6

*       B      5   2*4

*       B      6   2*5

****************************************************************************/

要搞清poc和frame的区别.

假设一个视频序列如下:

I B    B    P    B     B     P

我们编码是按I P B B P B B的顺序,这就是frame的编号.

而我们视频序列的播放序号是POC的序号,这里是乘以了2.

函数中先定义了如下三个参数:

int     i_nal_type;

nal存放的数据类型, 可以是sps,pps等多种.                  

int     i_nal_ref_idc;

nal的优先级,nal重要性的标志位.

前面两个参数虽然简单,但如果不参照标准,也不容易理解,所以标准中的句法表是很重要的,可以说是最关键的.

int     i_slice_type;

slice的类型,在x264中我的感觉好像一帧只有一个slice.如果确定了帧的类型,slice的类型也就确定了.

 

我们来看看编码器是如何区分读入的一帧是I帧,P帧,或者B帧,这个过程需要好好理解.

还以I       B B P B   B     P为例.

 

if( h->i_frame % (h->param.i_iframe * h->param.i_idrframe) == 0 ){

确定这是立即刷新片.

}

         这里很好理解.

但到了if( h->param.i_bframe > 0 )//可以B帧编码时.

就有问题了.

注意我们编完I帧后碰到了一个B帧,这时我们先不对它进编码.而是采用frame = x264_encoder_frame_put_from_picture( h, h->frame_next, pic )函数将这个B帧放进h->frame_next中.

好,这里出现了h->frame_next,在h中同时定义了下面几个帧数组用以实现帧的管理.

x264_frame_t   *bframe_current[X264_BFRAME_MAX]; /* store the sequence of b frame being encoded */

    x264_frame_t    *frame_next[X264_BFRAME_MAX+1];   /* store the next sequence of frames to be encoded *///搞清意义,下一个帧,而不一定是B帧.

    x264_frame_t    *frame_unused[X264_BFRAME_MAX+1]; /* store unused frames */

注意区分这3个数组.

同时还有下面4个函数(定义在/ENCODER/encoder.c中).

x264_encoder_frame_put_from_picture();

x264_encoder_frame_put();

x264_encoder_frame_get();

x264_frame_copy_picture();

这3个数组和4个函数可以说完成了整个帧的类型的判定问题.这个里面if ,else语句较多,容易使人迷惑.但我们只要把握下面一个观点就可以看清实质:在不对P帧进行编码之前,我们不对B帧进行编码,只是把B帧放进缓冲区(就是前面提到的数组).

比如视频序列:I     B B P B B P

先确立第一个帧的类型,然后进行编码.然后是2个B帧,我们把它放进缓冲区数组.然后是P帧,我们可以判定它的类型并进行编码.同时,我们将缓冲区的B帧放进h->bframe_current[i],不过这时P帧前的两个B帧并没有编码.当读到P帧后面的第一个B帧时,我们实际上才将h->bframe_current数组中的第一个B帧编码,也就是将在I帧后面的第一个B帧(说成P帧前面的第一个B帧容易误解J)编码.

依此类推,把握好上面4个函数的调用流程和指针操作的用法,就可以将帧的类型判定这个问题搞明白了.

F.      然后是速率控制(先不说这个,因为它对编码的流程影响不大),看看建立参考帧列表的操作,也就是

x264_reference_build_list( h, h->fdec->i_poc ); (定义在/ENCODER/encoder.c中).

光看这个函数是不行的,它是和后面的这个函数(如下)一起配合工作的.

if( i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE )//B帧时.

    {

        x264_reference_update( h );

}

     If条件是判断当前帧是否是B帧,如果是的话就不更新参考列表,因为B帧本来就不能作为参考帧嘛!如果是I帧或P帧的话,我们就更新参考帧列表.

我们看到了一个for循环,两个do—while循环.这是实现的关键,具体看代码,不好用语言说明白.

G.     进入另一个复杂的领域:写slice的操作,刚开使挺简单,如我下面的注释.

/* ---------------------- Write the bitstream -------------------------- */

    /* Init bitstream context */

    h->out.i_nal = 0;//out的声明在bs.h中.

    bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream );//空出8位.

 

    /* Write SPS and PPS */

    if( i_nal_type == NAL_SLICE_IDR )//不是每次都要写SPS and PPS,只有碰见立即刷新片时才写.

    {

        /* generate sequence parameters */

        x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST );

        x264_sps_write( &h->out.bs, h->sps );

        x264_nal_end( h );

 

        /* generate picture parameters */

        x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST );

        x264_pps_write( &h->out.bs, h->pps );

        x264_nal_end( h );

}

不过看下面那个函数(就进入了复杂的领域).

H.     x264_slice_write()(定义在/ENCODER/encoder.c中),这里面是编码的最主要部分,下面仔细分析.

前面不说,看下面这个循环,它是采用for循环对一帧图像的所有块依次进行编码.

for( mb_xy = 0, i_skip = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )//h->sps->i_mb_width指的是从宽度上说有多少个宏快.对于宽度也就是288 / 16 = 18

    {

        const int i_mb_y = mb_xy / h->sps->i_mb_width;

        const int i_mb_x = mb_xy % h->sps->i_mb_width;//这两个变量是定义宏块的位置.而不是指宏块中元素的位置.

 

        /* load cache */

        x264_macroblock_cache_load( h, i_mb_x, i_mb_y );//是把当前宏块的up宏块和left宏块的intra4x4_pred_mode,non_zero_count加载进来,放到一个数组里面,这个数组用来直接得到当前宏块的左侧和上面宏块的相关值.要想得到当前块的预测值,要先知道上面,左面的预测值,它的目的是替代getneighbour函数.

/* analyse parameters

         * Slice I: choose I_4x4 or I_16x16 mode

         * Slice P: choose between using P mode or intra (4x4 or 16x16)

         * */

        TIMER_START( i_mtime_analyse );

        x264_macroblock_analyse( h );//定义在analyse.h中.

        TIMER_STOP( i_mtime_analyse );

 

        /* encode this macrobock -> be carefull it can change the mb type to P_SKIP if needed */

        TIMER_START( i_mtime_encode );

        x264_macroblock_encode( h );//定义在Enc/encoder.c中.

        TIMER_STOP( i_mtime_encode );

截止到这就已经完成编码的主要过程了,后面就是熵编码的过程了(我也没看到那,但认为前面才是编码的主要过程).下面对这个过程进行分析.

A.     x264_macroblock_cache_load( h, i_mb_x, i_mb_y );它是将要编码的宏块的周围的宏块的值读进来, 要想得到当前块的预测值,要先知道上面,左面的预测值,它的作用相当于jm93中的getneighbour函数.

B.      进入x264_macroblock_analyse( h )函数(定义在/Enc/analyse.c中,这里涉及到了函数指针数组,需要好好复习,个人认为这也是x264代码最为复杂的一个地方了).既然已经将该宏块周围的宏块的值读了出来,我们就可以对该宏块进行分析了(其实主要就是通过计算sad值分析是否要将16*16的宏块进行分割和采用哪种分割方式合适).

看似很复杂,但我们只要把握一个东西就有利于理解了:

举个生活中的例子来说:

如果你有2元钱,你可以去买2袋1元钱的瓜子,也可以买一袋2元钱的瓜子,如果2袋1元钱的瓜子数量加起来比1袋2元钱的瓜子数量多,你肯定会买2袋1元的.反之你会去买那2元1袋的.

具体来说,对于一个16*16的块,

如果它是I帧的块,我们可以将它分割成16个4*4的块,如果这16个块的sad加起来小于按16*16的方式计算出来的sad值,我们就将这个16*16的块分成16个4*4的块进行编码(在计算每个4*4的块的最小sad值时已经知道它采用何种编码方式最佳了),否则采用16*16的方式编码(同样我们也已知道对它采用哪种编码方式最为合适了.

如果它是P帧或B帧的块,同样是循环套循环,但更为复杂了,可以看我在analyse.c中的注释.

这里还要注意的是提到了

x264_predict_t      predict_16x16[4+3];

typedef void (*x264_predict_t)( uint8_t *src, int i_stride );

这是函数指针数组,有很多对它的调用.

C.     退出x264_macroblock_analyse( h )函数,进入x264_macroblock_encode( )函数(定义在/ENCODER/macroblock.c中).

我拿宏块类型为I_16*16为例.

if( h->mb.i_type == I_16x16 )

    {

        const int i_mode = h->mb.i_intra16x16_pred_mode;

        /* do the right prediction */

        h->predict_16x16[i_mode]( h->mb.pic.p_fdec[0], h->mb.pic.i_fdec[0] );//这两个参数的关系.

                                                                   //涉及到x264_predict_t(函数指针数组),声明在core/predict.h中,core/predict.c里有不同定义.

        /* encode the 16x16 macroblock */

        x264_mb_encode_i16x16( h, i_qscale );//

/* fix the pred mode value */

       …     }

我们看到h->predict_16x16[i_mode]( h->mb.pic.p_fdec[0], h->mb.pic.i_fdec[0] );只调用了一次,这是因为在x264_macroblock_analyse( )中我们已经确定了采用4种方式中的哪种最合适.而在x264_macroblock_analyse( )中判定一个块是否为I_16*16,我们调用了四次.这是因为当时我们需要拿最小的sad值进行比较.

继续,是x264_mb_encode_i16x16( h, i_qscale )函数(定义在/ENCODER/macroblock.c中).在这个函数中我们就可以看到量化,zig-扫描等函数了,这些都是直来直去的,需要的只是我们的细心和对数学知识的掌握了

c)       到这里还没完,我们接着看

void x264_macroblock_encode( x264_t *h ){

…….前面省略.

执行到下面这条语句,看看下面是干啥的.

 

    /* encode chroma */

    i_qscale = i_chroma_qp_table[x264_clip3( i_qscale + h->pps->i_chroma_qp_index_offset, 0, 51 )];

    if( IS_INTRA( h->mb.i_type ) )

    {

        const int i_mode = h->mb.i_chroma_pred_mode;

        /* do the right prediction */

        h->predict_8x8[i_mode]( h->mb.pic.p_fdec[1], h->mb.pic.i_fdec[1] );

        h->predict_8x8[i_mode]( h->mb.pic.p_fdec[2], h->mb.pic.i_fdec[2] );

 

        /* fix the pred mode value */

        h->mb.i_chroma_pred_mode = x264_mb_pred_mode8x8_fix[i_mode];

    }

 

    /* encode the 8x8 blocks */

x264_mb_encode_8x8( h, !IS_INTRA( h->mb.i_type ), i_qscale );//对色度块进行编码了.

到这我们可以看到原来我们在这前面是对宏块中的亮度系数进行了编码,我们到上面那个函数才开始对色度系数进行编码.进入x264_mb_encode_8x8()函数看到for循环里面有个2可以证明是对2个色度系数进行编码,想法没错.

那下面这些又是干啥的呢?它们是计算cbp系数看需要对残差(包括ac,dc)中的哪个系数进行传输的.

 

    /* Calculate the Luma/Chroma patern and non_zero_count */

    if( h->mb.i_type == I_16x16 )

    {

        h->mb.i_cbp_luma = 0x00;

        for( i = 0; i < 16; i++ )

        {

            const int nz = array_non_zero_count( h->dct.block[i].residual_ac, 15 );

            h->mb.cache.non_zero_count[x264_scan8[i]] = nz;

            if( nz > 0 )

            {

                h->mb.i_cbp_luma = 0x0f;

            }

        }

    }

    else

    {

        h->mb.i_cbp_luma = 0x00;

        for( i = 0; i < 16; i++ )

        {

            const int nz = array_non_zero_count( h->dct.block[i].luma4x4, 16 );//统计非0个数.

            h->mb.cache.non_zero_count[x264_scan8[i]] = nz;

            if( nz > 0 )

            {

                h->mb.i_cbp_luma |= 1 << (i/4);// %16的意义.

            }

        }

    }

 

    /* Calculate the chroma patern *///色度的cbp有3种方式.

    h->mb.i_cbp_chroma = 0x00;

    for( i = 0; i < 8; i++ )

    {

        const int nz = array_non_zero_count( h->dct.block[16+i].residual_ac, 15 );

        h->mb.cache.non_zero_count[x264_scan8[16+i]] = nz;

        if( nz > 0 )                      

        {

            h->mb.i_cbp_chroma = 0x02;    /* dc+ac (we can't do only ac) */

        }

    }

    if( h->mb.i_cbp_chroma == 0x00 &&

        ( array_non_zero_count( h->dct.chroma_dc[0], 4 ) > 0 || array_non_zero_count( h->dct.chroma_dc[1], 4 ) ) > 0 )

    {

        h->mb.i_cbp_chroma = 0x01;    /* dc only */

    }

 

    if( h->param.b_cabac )

    {

        if( h->mb.i_type == I_16x16 && array_non_zero_count( h->dct.luma16x16_dc, 16 ) > 0 )

            i_cbp_dc = 0x01;

        else

            i_cbp_dc = 0x00;

 

        if( array_non_zero_count( h->dct.chroma_dc[0], 4 ) > 0 )

            i_cbp_dc |= 0x02;

        if( array_non_zero_count( h->dct.chroma_dc[1], 4 ) > 0 )

            i_cbp_dc |= 0x04;

    }

 

    /* store cbp */

h->mb.cbp[h->mb.i_mb_xy] = (i_cbp_dc << 8) | (h->mb.i_cbp_chroma << 4) | h->mb.i_cbp_luma;

 

到这,基本上x264_macroblock_encode( h )(定义在Enc/encoder.c)基本上就分析完了.剩下的就是熵编码的部分了.以后的部分更需要的应该是耐心和数学知识吧,相对前面来说应该简单些.

 

l       总结:

1. 我对代码的理解应该还算比较深入,把代码的主线已经分析了出来,对代码中几个最难理解的地方(最难理解的地方就是帧的类型的判定,参考帧是如何管理的,一个16*16的块是采用到底需不需要分割,分割的话分成什么大小的,子块又采用何种预测方式,这些实际上就是整个编码的主线.)基本上已经明白,但有些过分复杂的函数的实现(或者涉及数学知识较多的地方)还有待深入研究,但我相信沿着这条主线应该能够继续深入下去,自己需要的是更多的时间和耐心. 自己需要的是更多的时间和耐心,争取以后能写出更详细更准确的流程分析,并尽量思考能改进的地方.

2.层次性,就像网络的7层结构一样,每一帧图像也可以分成很多层,只有对每层的语法结构(具体来说就是各个结构体中变量的意思)有了很好的理解,才有可能真正认清代码,这需要对标准认真研习.比如说量化参数,就在3个地方有定义,不读标准根本不会明白意思.

3. 很多过分复杂的东西不容易在本文中表达出来(比如说预测部分),只有通过自己的钻研才能真正悟到,直觉也很重要,还有就是信心了.看这种程序的收获就好像是真地肉眼看到了原子那样.

4.由于代码过分复杂,对某些函数的实现过程还没能彻底理解,比如说x264_macroblock_cache_load()函数的具体实现过程,我只是知道它的功能,实现过程还有待认真理解.dct变换是如何实现的,是如何计算残差的等等,这些都需要很多功夫,当然这里也需要大家的共同学习和交流.实现分工阅读不同代码部分并进行交流,才有可能对代码做到彻底的理解.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/455709.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目启动居然如此重要!

项目的启动阶段比较短&#xff0c;项目经理往往容易忽视这个阶段&#xff0c;但是&#xff0c;项目的启动却具有着重要的意义。 定基调&#xff1a; 基调包括工作的节奏、团队氛围和沟通风格等。 一首歌的第一句决定了这首歌的基调&#xff0c;如何唱好这第一句就是项目启动所要…

mysql数据库导入导出文件sql文件

window下 1.导出整个数据库 mysqldump -u 用户名 -p 数据库名 > 导出的文件名 mysqldump -u dbuser -p dbname > dbname.sql 2.导出一个表 mysqldump -u 用户名 -p 数据库名 表名> 导出的文件名 mysqldump -u dbuser -p dbname users> dbname_users.sql 3.导出…

Android Studio主题设置、颜色背景配置

2019独角兽企业重金招聘Python工程师标准>>> color-themes 效果展示 打开http://color-themes.com/有很多样式可供选择 1. Monokai Sublime Text 3(color theme) 2. Solarized Light (color theme) 3. Visual Studio 2015 Dark(color theme) 导入方式 下载主…

JavaScript中的函数

js函数 *第一种是使用function语句定义函数 function abc(){alert(abc); }*第二种是在表达式中定义函数 var 函数名 function\(参数1&#xff0c;参数2&#xff0c;…\){函数体};//例如&#xff1a;//定义var add function\(a,b\){return ab;}//调用函数document.write\(a…

x264源代码分析1。fread()

相关说明:1. 使用版本: x264-cvs-2004-05-11 2. 这次的分析基本上已经将代码中最难理解的部分做了阐释,对代码的主线也做了剖析,如果这个主线理解了,就容易设置几个区间,进行分工阅读,将各个区间击破了. 3. 需要学习的知识:a) 编码器的工作流程.b) H.264的码流结构,像x264_sp…

在centos下安装pycrypto报错 RuntimeError: autoconf error

解决&#xff1a;yum -y install gcc File "/usr/lib64/python3.6/distutils/dist.py", line 974, in run_command cmd_obj.run() File "/usr/lib64/python3.6/distutils/command/build.py", line 135, in run self.run_command(cm…

Java多线程实现异步调用

在Java平台,实现异步调用的角色有如下三个角色&#xff1a;调用者、 提货单 、真实数据&#xff0c;一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单 .然后在过一断时间后凭提货单来获取真正的数据.去蛋糕店买蛋糕&#xff0c;不需要等蛋糕做出来(假设现做要很长…

sql server 2008 r2卸载重装_免费下载:Intouch软件、Windows操作系统、SQL数据库,VB6.0、C#...

为大家整理了常用的Windows操作系统和安装软件&#xff0c;基本上都是经过我们项目测试OK的版本&#xff0c;以后项目调试就齐全了&#xff0c;不用再“东奔西走”&#xff0c;“小鹿乱撞”了。整理不易&#xff0c;若对您有帮助请关注并转发&#xff0c;以便帮助到更多的人。I…

Android ToolBar 使用完全解析

ToolBar简介 ToolBar是Android 5.0推出的一个新的导航控件用于取代之前的ActionBar&#xff0c;由于其高度的可定制性、灵活性、具有Material Design风格等优点&#xff0c;越来越多的应用也用上了ToolBar&#xff0c;比如常用的知乎软件其顶部导航栏正是使用ToolBar。官方考虑…

【零散积累】传输文件(sz/rz/scp命令)

来自wiki迁移页面路径&#xff1a;刘旺的主页 / 个人零散积累 / 01> 传输文件&#xff08;sz/rz/scp命令&#xff09; 工作中的传输文件会出现在linux之间&#xff0c;或者linux与windows之间。 一、怎么实现linux与windows之间的文件传输&#xff1f; 1.sz和rz是什么 s…

x264_macroblock_cache_load()

功能:完成将已编码数据参数和待编码数据装入到h->mb.cache中,下图是BUF中存储的数据在以MB为单位的时候的存储顺序 x264_macroblock_cache_load( h, i_mb_x, i_mb_y );//是把当前宏块的up宏块和left宏块的intra4x4_pred_mode&#xff0c;non_zero_count加载进来&#xff0c…

U(优)盘安装FreeBSD-9.0+GNOME_lite桌面

贴图在我的主页&#xff1a;http://hi.baidu.com/daodej/item/26313f4fc3db51ef1f19bcc6 修订于&#xff1a;2012/07/04 标题&#xff1a;U(优)盘安装FreeBSD-9.0GNOME_lite桌面&#xff0c;boot0启动XP(Windows)、FreeBSD、Ubuntu(Linux)三系统 【黑括号表示说明&#xff0c;中…

【零散积累】 vim常用操作

类型 操作 含义 删除 dd 删除游标所在的一整行(常用) ndd n为数字。删除光标所在的向下n行&#xff0c;例如20dd则是删除光标所在的向下20行 d1G 删除光标所在到第一行的所有数据 dG 删除光标所在到最后一行的所有数据 d$ 删除光标所在处&#xff0c;到该…

生活中常见物联网实例_物联网网关常见问题解答(一)

1.为什么物联网解决方案需要网关&#xff1f;物联网网关弥合了设备&#xff0c;传感器&#xff0c;设备&#xff0c;系统和云之间的通信鸿沟。通过系统地连接云&#xff0c;物联网网关提供了本地处理和存储&#xff0c;并具有基于传感器输入的数据自主控制现场设备的功能。物联…

predict_16x16[i_mode]( p_dst, i_stride )lowres

h->predict_16x16[i_mode]( p_dst, i_stride ); 计算对应预测模式时的预测采样值。输出放到dst指向的数组中。Pred0ct_16x16是7个元素指向的数组&#xff0c;数组的每个元素是一个指向函数的指针变量&#xff0c;在x264_predict_16x16_init函数初始这个指针数组。7个元素分…

【零散积累】shell脚本学习

来自wiki迁移页面路径&#xff1a;刘旺的主页 / 个人零散积累 / 03> shell脚本学习 case Shell case语句&#xff08;多分支条件判断&#xff09; $( ) Linux—shell中$(( ))、$( )、与${ }的区别 - chengd - 博客园 在bash中&#xff0c;$( )与 &#xff08;反引号&…

mysql 表锁-解锁

遇到问题“”用工具navicat打开一张表的时候&#xff0c;有的时候会发现这张表怎么打不开&#xff0c;关了navicat工具&#xff0c;再打开&#xff0c;也是同样的状态。查看表锁&#xff1a;show OPEN TABLES where In_use > 0;查看是否是表锁住了。-- 查看进程号 show proc…

alsa 测试 linux_Electron 构建步骤 (Linux)

遵循下面的引导&#xff0c;在 Linux 上构建 Electron .PrerequisitesPython 2.7.x. 一些发行版如 CentOS 仍然使用 Python 2.6.x &#xff0c;所以或许需要 check 你的 Python 版本&#xff0c;使用 python -V.Node.js v0.12.x. 有很多方法来安装 Node. 可以从 Node.js下载原文…

JavaScript中的数学对象Math

js数学对象Math //四舍五入 var res Math.round(5.921);//获取最大值 var res Math.max(10,23,523,43,65,46,32,32);//获取最小值 var res Math.min(12312,324,32,42,3,23,412,4332,21,3,-1);//获取绝对值 var res Math.abs(-100);//退一取整 var res Math.floor(1.9);//…

centos7-安装mysql5.6.36

本地安装了mysql5.7, 但和springboot整合jpa时会出现 hibernateException, 不知道为什么, 换个mysql5.6版本的mysql, 源码安装, cmake一直过不去, 后来改成rpm安装 1, 获取mysql5.6 ftp://ftp.mirrorservice.org/sites/ftp.mysql.com/Downloads/MySQL-5.6/ 下载: 解压: 其中…