Quantcast
Channel: Interact^Influence
Viewing all 45 articles
Browse latest View live

追拍

$
0
0

要学H.264也不容易,涉及到的知识可谓是方方面面(代码,人体视觉系统构造,实际拍摄场景等等,因为它就是利用这些原理,来做到数据压缩的),看了一段时间的论文,书,对大体的理论知识算是有了个初步的掌握,想要一下吃进去不大现实,所以现在就先从简单的知识入手,记录一些阅读中遇到的认为有价值的知识。

今天来翻译(应该算看了英文的东西,然后用中文写点笔记)下照相有关的东西,主要参考资料Panning (camera),也就是我们日常所说的追拍。

比如你的小狗在跑,你想拍下它的样子,你就要随着它跑动的方位来移动你的镜头,当然是在拍摄过程当中,并且你移动镜头速度要和它跑动的速度差不多,就是镜头和狗相对静止,然后背景感觉在运动的效果。快门速度不能太快也不能太慢(太短了背景不会模糊,太长了整个画面都会模糊)。
效果图可以参见WikiPedia上的Racing Car,https://en.wikipedia.org/wiki/File:DTM_Mercedes_W204_DiResta09_amk.jpg。

File:DTM Mercedes W204 DiResta09 amk.jpg

当然我们这里说的追拍是指水平(horizontal plane)移动追拍,还有一种追拍是垂直移动的,叫做Tilt-shift拍摄,我们不考虑。

所以要想拍好这样的照片移动镜头的稳定性也是很重要的,所以有人把相机固定在三/单脚架上,或者更专业的是为相机架设一个固定的轨道,让相机在轨道上运行(电视里面拍戏经常见,不是吗)。

看完这个描述,你会觉得这不很简单吗?为什么会根H.264还有关系?其实是在Motion Compensation(MC)当中可能会用到这个。

参考资料:

https://en.wikipedia.org/wiki/Tilt_(camera)

https://en.wikipedia.org/wiki/Panning_(camera)


Exponential-Golomb coding

$
0
0

参考资料:

http://en.wikipedia.org/wiki/Exponential-Golomb_coding

http://zh.wikipedia.org/zh/指数哥伦布码

Information technology — Coding of audio-visual objects — Part 10: Advanced Video Coding

摘抄自以上资料,简单总结。

指數哥倫布碼(Exp-Golomb code),一种壓縮編碼方法。
用来表示非负整数的k阶指数哥伦布码可用如下步骤生成:
1. 将数字以二进制形式写出,去掉最低的k个比特位,之后加1
2. 计算留下的比特数,将此数减一,即是需要增加的前导零个数(注意是比特位数,非该比特串表示的值)
3. 将第一步中去掉的最低k个比特位补回比特串尾部
0阶指数哥伦布码如下所示:

0 => 1 => 1
1 => 10 => 010
2 => 11 => 011
3 => 100 => 00100
4 => 101 => 00101
5 => 110 => 00110
6 => 111 => 00111
7 => 1000 => 0001000
8 => 1001 => 0001001
...

从二进制比特串形式来看,0阶哥伦布编码的码字(codeword)由3部分构成:
码字 = [M个0] + [1] + [内容]
内容也是M位数据,所以每个0阶哥伦布码的位的长度为2M + 1,每个码字由原始的数字(codenumber)产生。

比如上面的数字7,二进制表示为111,0阶编码,所以不用去最后的比特为,加1之后变成1000,比特数为4位,所以前缀需要增加3(4-1)个0,即0001000,0阶所以结尾也不需要补码,于是最终码字就为0001000。

那如何解码呢?
参见如下伪代码

leadingZeroBits = −1
for (b = 0; !b; leadingZeroBits++)
	b = read_bits(1)

codeNum = 2^(leadingZeroBits + k) − 2^k + read_bits(leadingZeroBits + k)

这里类似于2^k这种写法表示幂运算,对于通常H.264当中用的是0阶的,所以可以简化成如下图

Exponential-Golomb Decoding

这里read_bits(...)的返回值使用高位在先的二进制无符号整数表示

二进制比特串       长度             解析值
1001             1               0
001 1001         5               5
01 1010          3               2
010              3               1
000 1011         7               10
0001 001         7               8

如上表,传入的比特串可能多余实际需要的数据,我们只需要解析需要的部分就可以了。

P.S.
为什么叫做指数哥伦布编码?
因为它对信源符号的分组大小按照指数增长。

一步一步解析H.264码流的NALU(SPS,PSS,IDR)

$
0
0

之前有说过H.264比较复杂,我是打算一块一块来分析。这里是学习笔记以及自己的理解,很多可能是摘抄的相关资料,感谢原始作者!理解错误的地方也希望大家指出。
注意:目前处于草稿状态,不定期更新!

在了解了H.264编码的基础介绍之后(Overview of the H.264/AVC Video Coding Standard,H.264-MPEG-4 Part 10 White Paper,ISO_IEC_14496-10_2012,新一代视频压缩编码标准H.264,H.264码流结构解析等等有非常多的资料,这里就不一一列举了,网上有很多,然后天之骄子/firstime还有李世平/Peter Lee这些前辈写的文章),这么多资料我也是没有完全看懂,我也是采取能看懂的尽量看懂,不能看懂的多看几遍(这些资料交换看/翻来覆去的看有帮助你理解原来不懂的东西),反正是对H.264有了个大概的理解。

我看这类编/解码有个习惯就是从编/解码出来的数据文件下手。因为无论如何复杂,最终的文件(字节流)肯定是符合某种规范的。

如果你打算继续往下看,你对H.264的理解基本上应该知道VCL和NAL是什么东西,知道Exp-Golomb/Huffman编码,码流(bitstream)是由一个个的NALU组成等等这一类的基本知识。

首先我们希望有种可以分析H.264码流的工具,这样可以让我们直观的了解,但是不幸的是类似这样的工具都太贵,多数许可证要上千美金,不过幸好我们可以找到21天试用版或者缺少功能的演示版。
我在网上搜索了很多相关的工具,比如CodecVisa,StreamEye以及VM Analyzer,这些都可以玩玩。

还有个问题,码流文件去哪里找?我在网上一个人的网站看到有下载,但是解压需要密码,我给它写信,期盼着他能给我密码,不幸的是他还没有回,然后我就继续找,其实可以不用这么麻烦,我们可以自己生成码流文件,JM代码里面有个foreman_part_qcif.yuv,你用它的lencod.exe命令先把它编码成H.264码流,这样你就还得先了解下JM是什么,如何编译,如何使用,不过这些都很简单。YUV视频序列也可以到网络上去下载,这个很多。

下载YUV视频序列 http://trace.eas.asu.edu/yuv/
H.264测试模型/文档 http://iphome.hhi.de/suehring/tml/

http://wftp3.itu.int/av-arch/jvt-site/

李世平 http://blog.csdn.net/sunshine1314
天之骄子 http://bbs.chinavideo.org/viewthread.php?tid=988

这里我查看码流用的工具是StreamEye,码流文件是foreman_part_qcif.yuv编码得来的。
这些工具怎么用就不介绍了,无非就是看视频有哪些/类帧组成,各个属性(Header/MacroBlock/Picture)是什么。

下面这段信息是从Headers Info拷贝出来的,粗看下它是SPS,PPS和Slice Header,那这有什么用,这些数据是什么意思?

  [00]seq_parameter_set_rbsp() {
    profile_idc                                    = 66 (Baseline)
    constraint_set0_flag                           = 0 (false)
    constraint_set1_flag                           = 0 (false)
    constraint_set2_flag                           = 0 (false)
    constraint_set3_flag                           = 0 (false)
    constraint_set4_flag                           = 0 (false)
    constraint_set5_flag                           = 0 (false)
    reserved_zero_2bits                            = 0
    level_idc                                      = 30
    seq_parameter_set_id                           = 0
    if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144) {
      chroma_format_idc                            = na
      if (chroma_format_idc == 3)
        separate_colour_plane_flag                 = na
      bit_depth_luma_minus8                        = na
      bit_depth_chroma_minus8                      = na
      qpprime_y_zero_transform_bypass_flag         = na
      seq_scaling_matrix_present_flag              = na
      if (seq_scaling_matrix_present_flag)
        for (i = 0; i < 8; i++) {
          seq_scaling_list_present_flag[0]         = na
          if (seq_scaling_list_present_flag[0])
            scaling_list_4x4[00]                   = na
            scaling_list_4x4[01]                   = na
            scaling_list_4x4[02]                   = na
            scaling_list_4x4[03]                   = na
            scaling_list_4x4[04]                   = na
            scaling_list_4x4[05]                   = na
            scaling_list_4x4[06]                   = na
            scaling_list_4x4[07]                   = na
            scaling_list_4x4[08]                   = na
            scaling_list_4x4[09]                   = na
            scaling_list_4x4[10]                   = na
            scaling_list_4x4[11]                   = na
            scaling_list_4x4[12]                   = na
            scaling_list_4x4[13]                   = na
            scaling_list_4x4[14]                   = na
            scaling_list_4x4[15]                   = na
          seq_scaling_list_present_flag[1]         = na
          if (seq_scaling_list_present_flag[1])
            scaling_list_4x4[00]                   = na
            scaling_list_4x4[01]                   = na
            scaling_list_4x4[02]                   = na
            scaling_list_4x4[03]                   = na
            scaling_list_4x4[04]                   = na
            scaling_list_4x4[05]                   = na
            scaling_list_4x4[06]                   = na
            scaling_list_4x4[07]                   = na
            scaling_list_4x4[08]                   = na
            scaling_list_4x4[09]                   = na
            scaling_list_4x4[10]                   = na
            scaling_list_4x4[11]                   = na
            scaling_list_4x4[12]                   = na
            scaling_list_4x4[13]                   = na
            scaling_list_4x4[14]                   = na
            scaling_list_4x4[15]                   = na
          seq_scaling_list_present_flag[2]         = na
          if (seq_scaling_list_present_flag[2])
            scaling_list_4x4[00]                   = na
            scaling_list_4x4[01]                   = na
            scaling_list_4x4[02]                   = na
            scaling_list_4x4[03]                   = na
            scaling_list_4x4[04]                   = na
            scaling_list_4x4[05]                   = na
            scaling_list_4x4[06]                   = na
            scaling_list_4x4[07]                   = na
            scaling_list_4x4[08]                   = na
            scaling_list_4x4[09]                   = na
            scaling_list_4x4[10]                   = na
            scaling_list_4x4[11]                   = na
            scaling_list_4x4[12]                   = na
            scaling_list_4x4[13]                   = na
            scaling_list_4x4[14]                   = na
            scaling_list_4x4[15]                   = na
          seq_scaling_list_present_flag[3]         = na
          if (seq_scaling_list_present_flag[3])
            scaling_list_4x4[00]                   = na
            scaling_list_4x4[01]                   = na
            scaling_list_4x4[02]                   = na
            scaling_list_4x4[03]                   = na
            scaling_list_4x4[04]                   = na
            scaling_list_4x4[05]                   = na
            scaling_list_4x4[06]                   = na
            scaling_list_4x4[07]                   = na
            scaling_list_4x4[08]                   = na
            scaling_list_4x4[09]                   = na
            scaling_list_4x4[10]                   = na
            scaling_list_4x4[11]                   = na
            scaling_list_4x4[12]                   = na
            scaling_list_4x4[13]                   = na
            scaling_list_4x4[14]                   = na
            scaling_list_4x4[15]                   = na
          seq_scaling_list_present_flag[4]         = na
          if (seq_scaling_list_present_flag[4])
            scaling_list_4x4[00]                   = na
            scaling_list_4x4[01]                   = na
            scaling_list_4x4[02]                   = na
            scaling_list_4x4[03]                   = na
            scaling_list_4x4[04]                   = na
            scaling_list_4x4[05]                   = na
            scaling_list_4x4[06]                   = na
            scaling_list_4x4[07]                   = na
            scaling_list_4x4[08]                   = na
            scaling_list_4x4[09]                   = na
            scaling_list_4x4[10]                   = na
            scaling_list_4x4[11]                   = na
            scaling_list_4x4[12]                   = na
            scaling_list_4x4[13]                   = na
            scaling_list_4x4[14]                   = na
            scaling_list_4x4[15]                   = na
          seq_scaling_list_present_flag[5]         = na
          if (seq_scaling_list_present_flag[5])
            scaling_list_4x4[00]                   = na
            scaling_list_4x4[01]                   = na
            scaling_list_4x4[02]                   = na
            scaling_list_4x4[03]                   = na
            scaling_list_4x4[04]                   = na
            scaling_list_4x4[05]                   = na
            scaling_list_4x4[06]                   = na
            scaling_list_4x4[07]                   = na
            scaling_list_4x4[08]                   = na
            scaling_list_4x4[09]                   = na
            scaling_list_4x4[10]                   = na
            scaling_list_4x4[11]                   = na
            scaling_list_4x4[12]                   = na
            scaling_list_4x4[13]                   = na
            scaling_list_4x4[14]                   = na
            scaling_list_4x4[15]                   = na
          seq_scaling_list_present_flag[6]         = na
          if (seq_scaling_list_present_flag[6])
            scaling_list_8x8[00]                   = na
            scaling_list_8x8[01]                   = na
            scaling_list_8x8[02]                   = na
            scaling_list_8x8[03]                   = na
            scaling_list_8x8[04]                   = na
            scaling_list_8x8[05]                   = na
            scaling_list_8x8[06]                   = na
            scaling_list_8x8[07]                   = na
            scaling_list_8x8[08]                   = na
            scaling_list_8x8[09]                   = na
            scaling_list_8x8[10]                   = na
            scaling_list_8x8[11]                   = na
            scaling_list_8x8[12]                   = na
            scaling_list_8x8[13]                   = na
            scaling_list_8x8[14]                   = na
            scaling_list_8x8[15]                   = na
            scaling_list_8x8[16]                   = na
            scaling_list_8x8[17]                   = na
            scaling_list_8x8[18]                   = na
            scaling_list_8x8[19]                   = na
            scaling_list_8x8[20]                   = na
            scaling_list_8x8[21]                   = na
            scaling_list_8x8[22]                   = na
            scaling_list_8x8[23]                   = na
            scaling_list_8x8[24]                   = na
            scaling_list_8x8[25]                   = na
            scaling_list_8x8[26]                   = na
            scaling_list_8x8[27]                   = na
            scaling_list_8x8[28]                   = na
            scaling_list_8x8[29]                   = na
            scaling_list_8x8[30]                   = na
            scaling_list_8x8[31]                   = na
            scaling_list_8x8[32]                   = na
            scaling_list_8x8[33]                   = na
            scaling_list_8x8[34]                   = na
            scaling_list_8x8[35]                   = na
            scaling_list_8x8[36]                   = na
            scaling_list_8x8[37]                   = na
            scaling_list_8x8[38]                   = na
            scaling_list_8x8[39]                   = na
            scaling_list_8x8[40]                   = na
            scaling_list_8x8[41]                   = na
            scaling_list_8x8[42]                   = na
            scaling_list_8x8[43]                   = na
            scaling_list_8x8[44]                   = na
            scaling_list_8x8[45]                   = na
            scaling_list_8x8[46]                   = na
            scaling_list_8x8[47]                   = na
            scaling_list_8x8[48]                   = na
            scaling_list_8x8[49]                   = na
            scaling_list_8x8[50]                   = na
            scaling_list_8x8[51]                   = na
            scaling_list_8x8[52]                   = na
            scaling_list_8x8[53]                   = na
            scaling_list_8x8[54]                   = na
            scaling_list_8x8[55]                   = na
            scaling_list_8x8[56]                   = na
            scaling_list_8x8[57]                   = na
            scaling_list_8x8[58]                   = na
            scaling_list_8x8[59]                   = na
            scaling_list_8x8[60]                   = na
            scaling_list_8x8[61]                   = na
            scaling_list_8x8[62]                   = na
            scaling_list_8x8[63]                   = na
          seq_scaling_list_present_flag[7]         = na
          if (seq_scaling_list_present_flag[7])
            scaling_list_8x8[00]                   = na
            scaling_list_8x8[01]                   = na
            scaling_list_8x8[02]                   = na
            scaling_list_8x8[03]                   = na
            scaling_list_8x8[04]                   = na
            scaling_list_8x8[05]                   = na
            scaling_list_8x8[06]                   = na
            scaling_list_8x8[07]                   = na
            scaling_list_8x8[08]                   = na
            scaling_list_8x8[09]                   = na
            scaling_list_8x8[10]                   = na
            scaling_list_8x8[11]                   = na
            scaling_list_8x8[12]                   = na
            scaling_list_8x8[13]                   = na
            scaling_list_8x8[14]                   = na
            scaling_list_8x8[15]                   = na
            scaling_list_8x8[16]                   = na
            scaling_list_8x8[17]                   = na
            scaling_list_8x8[18]                   = na
            scaling_list_8x8[19]                   = na
            scaling_list_8x8[20]                   = na
            scaling_list_8x8[21]                   = na
            scaling_list_8x8[22]                   = na
            scaling_list_8x8[23]                   = na
            scaling_list_8x8[24]                   = na
            scaling_list_8x8[25]                   = na
            scaling_list_8x8[26]                   = na
            scaling_list_8x8[27]                   = na
            scaling_list_8x8[28]                   = na
            scaling_list_8x8[29]                   = na
            scaling_list_8x8[30]                   = na
            scaling_list_8x8[31]                   = na
            scaling_list_8x8[32]                   = na
            scaling_list_8x8[33]                   = na
            scaling_list_8x8[34]                   = na
            scaling_list_8x8[35]                   = na
            scaling_list_8x8[36]                   = na
            scaling_list_8x8[37]                   = na
            scaling_list_8x8[38]                   = na
            scaling_list_8x8[39]                   = na
            scaling_list_8x8[40]                   = na
            scaling_list_8x8[41]                   = na
            scaling_list_8x8[42]                   = na
            scaling_list_8x8[43]                   = na
            scaling_list_8x8[44]                   = na
            scaling_list_8x8[45]                   = na
            scaling_list_8x8[46]                   = na
            scaling_list_8x8[47]                   = na
            scaling_list_8x8[48]                   = na
            scaling_list_8x8[49]                   = na
            scaling_list_8x8[50]                   = na
            scaling_list_8x8[51]                   = na
            scaling_list_8x8[52]                   = na
            scaling_list_8x8[53]                   = na
            scaling_list_8x8[54]                   = na
            scaling_list_8x8[55]                   = na
            scaling_list_8x8[56]                   = na
            scaling_list_8x8[57]                   = na
            scaling_list_8x8[58]                   = na
            scaling_list_8x8[59]                   = na
            scaling_list_8x8[60]                   = na
            scaling_list_8x8[61]                   = na
            scaling_list_8x8[62]                   = na
            scaling_list_8x8[63]                   = na
          }
        }
      }
    log2_max_frame_num_minus4                      = 0 (4)
    pic_order_cnt_type                             = 0
    if (pic_order_cnt_type == 0)
      log2_max_pic_order_cnt_lsb_minus4            = 0 (4)
    else if (pic_order_cnt_type == 1) {
      delta_pic_order_always_zero_flag             = na
      offset_for_non_ref_pic                       = na
      offset_for_top_to_bottom_field               = na
      num_ref_frames_in_pic_order_cnt_cycle        = na
      for(i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++)
      }
    max_num_ref_frames                             = 10
    gaps_in_frame_num_value_allowed_flag           = 0
    pic_width_in_mbs_minus1                        = 10 (176)
    pic_height_in_map_units_minus1                 = 8 (144)
    frame_mbs_only_flag                            = 1
    if (!frame_mbs_only_flag)
      mb_adaptive_frame_field_flag                 = na
    direct_8x8_inference_flag                      = 0 (false)
    frame_cropping_flag                            = 0 (false)
    if (frame_cropping_flag) {
      frame_crop_left_offset                       = na
      frame_crop_right_offset                      = na
      frame_crop_top_offset                        = na
      frame_crop_bottom_offset                     = na
      }
    vui_parameters_present_flag                    = 0 (false)
    if (vui_parameters_present_flag)
      }
      vui_parameters()
    }
  [00]pic_parameter_set_rbsp() {
    pic_parameter_set_id                           = 0
    seq_parameter_set_id                           = 0
    entropy_coding_mode_flag                       = 0 (CAVLC)
    pic_order_present_flag                         = 0 (false)
    num_slice_groups_minus1                        = 0 (1)
    if (num_slice_groups_minus1 > 0) {
      slice_group_map_type                         = na
      if (slice_group_map_type == 0)
        for (iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++) {
        }
      else if (slice_group_map_type == 2)
        for (iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++) {
        }
      else if ((slice_group_map_type == 3) || (slice_group_map_type == 4) || (slice_group_map_type == 5)) {
        slice_group_change_direction_flag          = na
        slice_group_change_rate_minus1             = na
      } else if (slice_group_map_type == 6) {
        pic_size_in_map_units_minus1               = na
        for (i = 0; i <= pic_size_in_map_units_minus1; i++)
        }
      }
    num_ref_idx_l0_active_minus1                   = 9 (10)
    num_ref_idx_l1_active_minus1                   = 9 (10)
    weighted_pred_flag                             = 0 (false)
    weighted_bipred_idc                            = 0
    pic_init_qp_minus26                            = 0 (26)
    pic_init_qs_minus26                            = 0 (26)
    chroma_qp_index_offset                         = 0
    deblocking_filter_control_present_flag         = 0 (false)
    constrained_intra_pred_flag                    = 0 (false)
    redundant_pic_cnt_present_flag                 = 0 (false)
    }
    if (more_rbsp_data()) {
      transform_8x8_mode_flag                      = na
      pic_scaling_matrix_present_flag              = na
      if (pic_scaling_matrix_present_flag) {
        for (i = 0; i < 6 + 2 * transform_8x8_mode_flag; i++) {
          pic_scaling_list_present_flag[0]         = na
          if (pic_scaling_list_present_flag[0])
            scaling_list_4x4[0][00]                = na
            scaling_list_4x4[0][01]                = na
            scaling_list_4x4[0][02]                = na
            scaling_list_4x4[0][03]                = na
            scaling_list_4x4[0][04]                = na
            scaling_list_4x4[0][05]                = na
            scaling_list_4x4[0][06]                = na
            scaling_list_4x4[0][07]                = na
            scaling_list_4x4[0][08]                = na
            scaling_list_4x4[0][09]                = na
            scaling_list_4x4[0][10]                = na
            scaling_list_4x4[0][11]                = na
            scaling_list_4x4[0][12]                = na
            scaling_list_4x4[0][13]                = na
            scaling_list_4x4[0][14]                = na
            scaling_list_4x4[0][15]                = na
          pic_scaling_list_present_flag[1]         = na
          if (pic_scaling_list_present_flag[1])
            scaling_list_4x4[1][00]                = na
            scaling_list_4x4[1][01]                = na
            scaling_list_4x4[1][02]                = na
            scaling_list_4x4[1][03]                = na
            scaling_list_4x4[1][04]                = na
            scaling_list_4x4[1][05]                = na
            scaling_list_4x4[1][06]                = na
            scaling_list_4x4[1][07]                = na
            scaling_list_4x4[1][08]                = na
            scaling_list_4x4[1][09]                = na
            scaling_list_4x4[1][10]                = na
            scaling_list_4x4[1][11]                = na
            scaling_list_4x4[1][12]                = na
            scaling_list_4x4[1][13]                = na
            scaling_list_4x4[1][14]                = na
            scaling_list_4x4[1][15]                = na
          pic_scaling_list_present_flag[2]         = na
          if (pic_scaling_list_present_flag[2])
            scaling_list_4x4[2][00]                = na
            scaling_list_4x4[2][01]                = na
            scaling_list_4x4[2][02]                = na
            scaling_list_4x4[2][03]                = na
            scaling_list_4x4[2][04]                = na
            scaling_list_4x4[2][05]                = na
            scaling_list_4x4[2][06]                = na
            scaling_list_4x4[2][07]                = na
            scaling_list_4x4[2][08]                = na
            scaling_list_4x4[2][09]                = na
            scaling_list_4x4[2][10]                = na
            scaling_list_4x4[2][11]                = na
            scaling_list_4x4[2][12]                = na
            scaling_list_4x4[2][13]                = na
            scaling_list_4x4[2][14]                = na
            scaling_list_4x4[2][15]                = na
          pic_scaling_list_present_flag[3]         = na
          if (pic_scaling_list_present_flag[3])
            scaling_list_4x4[3][00]                = na
            scaling_list_4x4[3][01]                = na
            scaling_list_4x4[3][02]                = na
            scaling_list_4x4[3][03]                = na
            scaling_list_4x4[3][04]                = na
            scaling_list_4x4[3][05]                = na
            scaling_list_4x4[3][06]                = na
            scaling_list_4x4[3][07]                = na
            scaling_list_4x4[3][08]                = na
            scaling_list_4x4[3][09]                = na
            scaling_list_4x4[3][10]                = na
            scaling_list_4x4[3][11]                = na
            scaling_list_4x4[3][12]                = na
            scaling_list_4x4[3][13]                = na
            scaling_list_4x4[3][14]                = na
            scaling_list_4x4[3][15]                = na
          pic_scaling_list_present_flag[4]         = na
          if (pic_scaling_list_present_flag[4])
            scaling_list_4x4[4][00]                = na
            scaling_list_4x4[4][01]                = na
            scaling_list_4x4[4][02]                = na
            scaling_list_4x4[4][03]                = na
            scaling_list_4x4[4][04]                = na
            scaling_list_4x4[4][05]                = na
            scaling_list_4x4[4][06]                = na
            scaling_list_4x4[4][07]                = na
            scaling_list_4x4[4][08]                = na
            scaling_list_4x4[4][09]                = na
            scaling_list_4x4[4][10]                = na
            scaling_list_4x4[4][11]                = na
            scaling_list_4x4[4][12]                = na
            scaling_list_4x4[4][13]                = na
            scaling_list_4x4[4][14]                = na
            scaling_list_4x4[4][15]                = na
          pic_scaling_list_present_flag[5]         = na
          if (pic_scaling_list_present_flag[5])
            scaling_list_4x4[5][00]                = na
            scaling_list_4x4[5][01]                = na
            scaling_list_4x4[5][02]                = na
            scaling_list_4x4[5][03]                = na
            scaling_list_4x4[5][04]                = na
            scaling_list_4x4[5][05]                = na
            scaling_list_4x4[5][06]                = na
            scaling_list_4x4[5][07]                = na
            scaling_list_4x4[5][08]                = na
            scaling_list_4x4[5][09]                = na
            scaling_list_4x4[5][10]                = na
            scaling_list_4x4[5][11]                = na
            scaling_list_4x4[5][12]                = na
            scaling_list_4x4[5][13]                = na
            scaling_list_4x4[5][14]                = na
            scaling_list_4x4[5][15]                = na
          }
        }
      second_chroma_qp_index_offset                = na
      }
    }
  [00]slice_header() {
    nal_unit_header_svc_extension() {
      idr_flag                                     = na
      priority_id                                  = na
      no_inter_layer_pred_flag                     = na
      dependency_id                                = na
      quality_id                                   = na
      temporal_id                                  = na
      use_ref_base_pic_flag                        = na
      discardable_flag                             = na
      output_flag                                  = na
      }
    first_mb_in_slice                              = 0
    slice_type                                     = 7 (I slice)
    pic_parameter_set_id                           = 0
    frame_num                                      = 0
    if (!frame_mbs_only_flag) {
      field_pic_flag                               = na
      if (field_pic_flag)
        bottom_field_flag                          = na
      }
    if (nal_unit_type == 5)
      idr_pic_id                                   = 0
    if (pic_order_cnt_type == 0) {
      pic_order_cnt_lsb                            = 0
      if (pic_order_present_flag && !field_pic_flag)
        delta_pic_order_cnt_bottom                 = na
      }
    if (pic_order_cnt_type == 1 && !delta_pic_order_always_zero_flag) {
      delta_pic_order_cnt[0]                       = na
      if (pic_order_present_flag && !field_pic_flag)
        delta_pic_order_cnt[1]                     = na
      }
    if (redundant_pic_cnt_present_flag)
      redundant_pic_cnt                            = na
    if (slice_type == B)
      direct_spatial_mv_pred_flag                  = na
    if (slice_type == P || slice_type == SP || slice_type == B) {
      num_ref_idx_active_override_flag             = na
      if (num_ref_idx_active_override_flag) {
        num_ref_idx_l0_active_minus1               = na
        if (slice_type == B )
          num_ref_idx_l1_active_minus1             = na
        }
      }
    if (nal_unit_type == 20)
      ref_pic_list_mvc_modification()
    else
      ref_pic_list_modification()
    if ((weighted_pred_flag && (slice_type == P || slice_type == SP)) || (weighted_bipred_idc == 1 && slice_type == B))
      pred_weight_table()
    if (nal_ref_idc != 0)
      dec_ref_pic_marking()
    if (entropy_coding_mode_flag && slice_type != I && slice_type != SI)
      cabac_init_idc                               = na
    slice_qp_delta                                 = 2
    if (slice_type == SP || slice_type == SI) {
      if (slice_type == SP)
        sp_for_switch_flag                         = na
      slice_qs_delta                               = na
      }
    if (deblocking_filter_control_present_flag) {
      disable_deblocking_filter_idc                = na
      if (disable_deblocking_filter_idc != 1) {
        slice_alpha_c0_offset_div2                 = na
        slice_beta_offset_div2                     = na
        }
      }
    if (num_slice_groups_minus1 > 0 && slice_group_map_type >= 3 && slice_group_map_type <= 5)
      slice_group_change_cycle                     = na
    }

我们现在来分析,我们知道码流是由一个个的NAL Unit组成的,NALU是由NALU头和RBSP数据组成,而RBSP可能是SPS,PPS,Slice或SEI,目前我们这里SEI不会出现,而且SPS位于第一个NALU,PPS位于第二个NALU,其他就是Slice(严谨点区分的话可以把IDR等等再分出来)了。foreman_part_qcif.yuv只有3帧,那这里编码出来是不是就有5个NALU?我们这里可以大胆假设,然后仔细验证。
NALU头是什么东西,参见Spec的7.3 Syntax in tabular form,如果你有看过天之骄子的文章,就知道在Spec的7.3和7.4是相对应的,所以这两部分都要看,而且7.3就是编码算法的伪代码实现。C(ategory)和Descriptor都要熟悉,f(1),u(2),b(8),ue(v)等等是什么意思,这些在7.2和9.1都有详细说明,大概说下这里比如ue(v),se(v)等等这样的就是Exp-Golomb编码,f(1),u(2)这里就是通常的按位数,比如2位的无符号整数,32位的整数等等。

所以7.3和7.4一定要看明白,只有看明白了才能在码流基础上分析H.264。

现在我们来开始分析,下面是一段H.264码流文件的十六进制数据,所以你得有个十六进制编辑器。

00 00 00 01 67 42 00 1E F1 61 62 62 00 00 00 01 68 C8 A1 43 88 00

我们知道00 00 00 01是NALU的开始标记,所以你打开这个完整的码流文件应该可以看到5个00 00 00 01,所以这就是我们之前说的有5个NALU,分别是SPS,PPS和3个Slice。

先贴段数据,这是Spec(Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes)规定的,NALU的类型,现在我们只要看看SPS,PPS,IDR和Slice就行。

#define NALU_TYPE_SLICE    1
#define NALU_TYPE_DPA      2
#define NALU_TYPE_DPB      3
#define NALU_TYPE_DPC      4
#define NALU_TYPE_IDR      5
#define NALU_TYPE_SEI      6
#define NALU_TYPE_SPS      7
#define NALU_TYPE_PPS      8
#define NALU_TYPE_AUD      9
#define NALU_TYPE_EOSEQ    10
#define NALU_TYPE_EOSTREAM 11
#define NALU_TYPE_FILL     12

A) 我们先看第一个NALU的RBSP(8个字节)

67 42 00 1E F1 61 62 62

转换成二进制流

01100111 01000010 00000000 00011110 11110001 01100001 01100010 01100010

先看NALU头
forbidden_zero_bit
nal_ref_idc
nal_unit_type
这三个属性共占8位(Spec上都有写,分别占1,2和5位),那我们对着解析下就看出
forbidden_zero_bit = 0 // 0
nal_ref_idc = 3 // 11
nal_unit_type = 7 // 00111
这就对了,看看
#define NALU_TYPE_SPS 7
Spec当中后面有些放在if判断里的就是只有符合某个值的时候才会出现,我们这里nal_unit_type为7,不符合,所以直接跳过,进入到RBSP当中,这里是SPS,所以对照Spec
profile_idc
constraint_set0_flag
constraint_set1_flag
constraint_set2_flag
constraint_set3_flag
constraint_set4_flag
constraint_set5_flag
reserved_zero_2bits
level_idc
seq_parameter_set_id
这几个属性,直到seq_parameter_set_id之前都还比较好解析,我们就直接写出它们的值了
profile_idc = 66 // 01000010
constraint_set0_flag = 0 // 0
constraint_set1_flag = 0 // 0
constraint_set2_flag = 0 // 0
constraint_set3_flag = 0 // 0
constraint_set4_flag = 0 // 0
constraint_set5_flag = 0 // 0
reserved_zero_2bits = 0 // 00
level_idc = 30 // 00011110
对于seq_parameter_set_id,我们看到它是ue(v),这是一种Exp-Golomb编码,每个编码所占的位数不是固定的,我们现在还剩下的数据是11110001 01100001 01100010 01100010。
公式参考Spec(9.1 Parsing process for Exp-Golomb codes),

leadingZeroBits = −1
for (b = 0; !b; leadingZeroBits++)
	b = read_bits(1)

codeNum = 2^(leadingZeroBits) − 1 + read_bits(leadingZeroBits)

类似于2^k这种写法表示幂运算

过程就是读取1位,在这里结果是1,所以会跳出循环,但是leadingZeroBits++还是会执行,所以leadingZeroBits为0,后面read_bits也不会读取数据了。
codeNum = 2^0 - 1 + 0 = 0
也就是说编码为1的属性实际值为0
seq_parameter_set_id = 0 // Exp-Golomb解1
同样后面是if判断不会走到,现在直接到
log2_max_frame_num_minus4 = 0 // Exp-Golomb解1
pic_order_cnt_type = 0 // Exp-Golomb解1
log2_max_pic_order_cnt_lsb_minus4 = 0 // Exp-Golomb解1

max_num_ref_frames = 10 // 这里二进制流从0001开始了(前面的4个1被上面4个属性用掉了),所以有leadingZeroBits为3,结果就是2^3 - 1 + read_bits(011)

gaps_in_frame_num_value_allowed_flag = 0 // 0

pic_width_in_mbs_minus1 = 10 // Exp-Golomb解0001 011
pic_height_in_map_units_minus1 = 8 // Exp-Golomb解00010 01

对于Exp-Golomb不明白的请参见Exponential-Golomb coding解码部分,剩下的

frame_mbs_only_flag = 1 // 1

direct_8x8_inference_flag = 0 // 0
frame_cropping_flag = 0 // 0
vui_parameters_present_flag = 0 // 0

还剩下10两个位的数据没有用到,之前的这么多数据(除了NALU头之外的)都是seq_parameter_set_data,而根据Spec我们知道还有结尾补齐位

seq_parameter_set_rbsp( ) {
	seq_parameter_set_data( ) // 数据
	rbsp_trailing_bits( ) // 按字节补齐
}

补齐规则参见7.3.2.11 RBSP trailing bits syntax,实际就是按照字节对齐来补齐,所以这就是10这两位数据的由来。

回头看起来,这就是SPS的数据,也就是第一个NALU,同前面从Headers Info拷贝出来的SPS也是完全吻合的,所以这里我们就算是把Spec和实际的用法/码流对照起来了。另外值得说一下的就是从Headers Info拷贝出来的数据当中"na"就是未定义的,也就是if条件没有覆盖的情况。

B) 现在我们以同样的方式来看PPS(5个字节)

68 C8 A1 43 88

转换成二进制流

01101000 11001000 10100001 01000011 10001000

同样先看NALU头,解析结果如下
forbidden_zero_bit = 0 // 0
nal_ref_idc = 3 // 11
nal_unit_type = 8 // 01000
也就对应于
#define NALU_TYPE_PPS 8
就可以知道此处的RBSP是PPS
pic_parameter_set_id = 0 // Exp-Golomb解1
seq_parameter_set_id = 0 // Exp-Golomb解1
entropy_coding_mode_flag = 0 // 0
bottom_field_pic_order_in_frame_present_flag = 0 // 0
num_slice_groups_minus1 = 0 // Exp-Golomb解1

num_ref_idx_l0_default_active_minus1 = 9 // Exp-Golomb解000 1010
num_ref_idx_l1_default_active_minus1 = 9 // Exp-Golomb解0001 010

weighted_pred_flag = 0 // 0
weighted_bipred_idc = 0 // 00

pic_init_qp_minus26 = 0 // Exp-Golomb解1
pic_init_qs_minus26 = 0 // Exp-Golomb解1
chroma_qp_index_offset = 0 // Exp-Golomb解1

deblocking_filter_control_present_flag = 0 // 0
constrained_intra_pred_flag = 0 // 0
redundant_pic_cnt_present_flag = 0 // 0

还剩下1000这四位,这就是按字节补齐的数据。

C) 这就是Slice开始的数据了
先看部分数据(前4个字节)

65 88 84 02

转换成二进制流

01100101 10001000 10000100 00000010

同样先看NALU头,解析结果如下
forbidden_zero_bit = 0 // 0
nal_ref_idc = 3 // 11
nal_unit_type = 5 // 00101
也就对应于
#define NALU_TYPE_IDR 5
可以知道这个是IDR帧(关于什么是IDR,IDR和I片有什么区别)

first_mb_in_slice = 0 // Exp-Golomb解1
slice_type = 7 // Exp-Golomb解0001000 也就是I slice,关于slice_type请参考Table 7-6 – Name association to slice_type
pic_parameter_set_id = 0 // Exp-Golomb解1

frame_num = 0 // u(v)根据占用的位数(log2_max_frame_num_minus4 + 4)解出值 // 0000

对于frame_num这个属性要特别说下,它的Descriptor是u(v),那么我们查看u(v)得知
u(n): unsigned integer using n bits. When n is "v" in the syntax table, the number of bits varies in a manner dependent on the value of other syntax elements.
也就是说这个属性占用的位数是取决于其它属性的,那就再搜索下frame_num得到
frame_num is used as an identifier for pictures and shall be represented by log2_max_frame_num_minus4 + 4 bits in the bitstream.
于是我们就大概清楚了,frame_num占用的位数跟log2_max_frame_num_minus4相关,之前在SPS当中我们知道log2_max_frame_num_minus4 = 0,所以这里frame_num占用4位,也就是0000,解析出来也就是0,另外也需要知道frame_num有很多限制,比如在IDR当中必须为0,具体参见7.4.3 Slice header semantics。这里要指出的是,这是一份完整优秀的Spec,基本上已经涵盖了我们需要的所有东西,只是需要我们去找,去分析(尽管这个过程可能很麻烦,有时让人摸不着头脑,但是需要相信我们需要的答案就在里面)。

idr_pic_id = 0 // Exp-Golomb解1

pic_order_cnt_lsb = 0 // u(v)根据占用的位数(log2_max_pic_order_cnt_lsb_minus4 + 4)解出值 // 0000

剩下的000010

现在要进入ref_pic_list_modification( )这个function了,但是里面所有if判断条件不符合

然后进入dec_ref_pic_marking( )
no_output_of_prior_pics_flag = 0 // 0
long_term_reference_flag = 0 // 0

现在只剩下0010这四位了,我们继续补充3个字节(63 61 7C)进来01100011 01100001 01111100
于是我们继续做slice_qp_delta的解码,注意这里它的Descriptor是se(v),所以要先对进Exp-Golomb解码,然后进行mapping得出值。
0010 01100011 01100001 01111100 // 这里两个0,求出Exp-Golomb编码值为00100 // 长度5,后缀为0可以被解析成2 实际可以通过Exp-Golomb(2^2 - 1 + 0)算出值为3 然后代入(-1)^(k + 1) * Ceil(k divide 2)求出值为2。详细可以参见9.1.1 Mapping process for signed Exp-Golomb codes。

slice_qp_delta = 2 // 00100 // se(v)

到这里Slice Header就解析完成了。

暂时就到这里,需要说明的是,我们只写出了前三个NALU部分解析方法(第一个Slice,也就是IDR,我们只写出了Header部分,还有数据部分我们留到后面来分析),还剩两个Slice我们留着有必要的时候来分析。

H.264标记贴

Android Kitkat SDK 打包出现 Dex error

$
0
0

尝鲜Android Kitkat的同学很多人都遇到了下面这个错误。

[2013-11-01 16:58:07 - Dex Loader] Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
[2013-11-01 16:58:07 - Hello-Android] Conversion to Dalvik format failed: Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.

java.nio.BufferOverflowException
	at java.nio.Buffer.nextPutIndex(Buffer.java:499)
	at java.nio.HeapByteBuffer.putShort(HeapByteBuffer.java:296)
	at com.android.dex.Dex$Section.writeShort(Dex.java:818)
	at com.android.dex.Dex$Section.writeTypeList(Dex.java:870)
	at com.android.dx.merge.DexMerger$3.write(DexMerger.java:437)
	at com.android.dx.merge.DexMerger$3.write(DexMerger.java:423)
	at com.android.dx.merge.DexMerger$IdMerger.mergeUnsorted(DexMerger.java:317)
	at com.android.dx.merge.DexMerger.mergeTypeLists(DexMerger.java:423)
	at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:163)
	at com.android.dx.merge.DexMerger.merge(DexMerger.java:187)
	at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)
	at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)
	at com.android.dx.command.dexer.Main.run(Main.java:230)
	at sun.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.android.ide.eclipse.adt.internal.build.DexWrapper.run(DexWrapper.java:187)
	at com.android.ide.eclipse.adt.internal.build.BuildHelper.executeDx(BuildHelper.java:780)
	at com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder.build(PostCompilerBuilder.java:593)
	at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:728)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:199)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:239)
	at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:292)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:295)
	at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:351)
	at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:374)
	at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:143)
	at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:241)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

有人第一时间在Groups上提出了这个问题
Dex issues with latest SDK
但是目前也还没有得到官方的回答,看起来应该是build-tools的影响。

我试了下,项目版本在Android 4.1之上的基本都不会有这个问题,在4.1以下的目前应该都有这个问题。

这样子似乎只能等待官方答案。。。

有人把build-tools回滚到18.1.1据说可以解决这个问题。

如果有需要大家可以按这两个方法试试~~

P.S. 亲测 Linux和Windows下都有这个问题,有人说Mac OS下没有这个问题。。。只能跪了,另外同步AOSP代码真是个痛苦的过程

H.264预测之帧内预测

$
0
0

这是一篇阅读笔记,直接点击图片可以查看清晰大图。

参考资料
The H.264 Advanced Video Compression Standard, Second Edition,以下简称THAVCS
Information technology - Coding of audio-visual objects - Part 10: Advanced Video Coding,以下简称SPEC

CodecVisa
JM
foreman_part_qcif.264 这个是foreman_part_qcif.yuv通过JM 8.6转换来的

http://blog.csdn.net/stpeace/article/details/8114826

简单的理解帧内预测就是利用该帧里面已经编码和重构好的块来编码数据,具体做法就是用当前块减去预测块,得到的数据再编码

比如:

编码好的块 B
预测块 P
当前块 C

Delta = C - P
P是根据B预测来的,Delta是最终进行编码的数据,也就是我们经常说的Residual

对于亮度分量,P一般是4 x 4的块或者16 x 16的宏块(8 x 8的只在high profile当中出现),对于细节比较丰富的地方使用4 x 4的块,对于比较平坦的地方使用16 x 16的块的(这样做的原因就是通常块分的越细就需要越多的位来存放这些块自身的信息,但预测的殘差会比较小;块分的越大,存放块本身信息所占用比较少的位,预测的时候殘差就会占用更多的位,所以这是一个权衡)。并且我们一般记作4 × 4 Luma Prediction和16 × 16 Luma Prediction。
4 × 4 Luma Prediction有9种预测模式,参见THAVCS书的Figure 6.10和Figure 6.11,名字就不一一列举了,这里有截图。
4-x-4-intra-prediction-modes
那这么多预测模式我们到底使用哪一个是如何决定的呢?这里就涉及到一个SAE(Sum of Absolute Errors),这个SAE表示预测的错误或者偏差,明显SAE越大越不准确,所以这里我们当然选择SAE最小的那个,至于SAE是如何算出来的,我们暂时不考虑。
16 × 16 Luma Prediction有4种预测模式,参见THAVCS书的Figure 6.13,截图如下,当然选用那种模式跟上面的方法一样,也是看SAE。
16-x-16-intra-prediction-modes
16-x-16-intra-prediction-modes-descriptions

对于色度分量,P一般是8 x 8的块,记作8 × 8 Chroma Prediction。它也是有4种预测模式,跟16 × 16 Luma Prediction一样,只是模式的编号不一样,具体如下,DC(mode 0), Horizontal(mode 1),Vertical(mode 2)和Plane(mode 3)

知道这些总体上的知识之后,我们来稍微深入看看具体的,这个时候就需要用到CodecVisa了。打开码流,可以看到MB(MacroBlock)信息如下,
从MB统计信息(h.264-foreman-1st-frame-mb-statistics)来看,该Picture是I-Slice,一共有99个I-MBs,94个I_NxN类型,2个I_16x16_0_0_0类型,1个I_16x16_2_0_0类型,1个I_16x16_3_1_0类型以及1个I_16x16_2_0_1类型,具体这些类型的含义可以参见SPEC的Table 7-11 – Macroblock types for I slices。
h.264-foreman-1st-frame-mb-statistics
各个MB的分布情况如下,当然下图只能比较容易的区分出16 x 16的5个MB,
h.264-foreman-1st-frame-mb
另外第一个MB的详细信息如下,
h.264-foreman-1st-frame-1st-mb

I_16x16_0_0_0表示预测模型是0(Vertical),而且我们知道这是Y分量,我们可以对照CodecVisa验证。通过h.264-foreman-1st-frame-i_16x16_0_0_0-mb我们可以看见这个MB的预测值都是237,而且因为它的预测模型是Vertical,所以我们可以推理出,该MB上面对应的位置的值应该也都是237,通过CodecVisa查看对应位置的数据截图如h.264-foreman-1st-frame-i_16x16_0_0_0-mb-up-mb,可以看出确实是237,这与我们说的Vertical模式正好吻合。至于实际值是236,这当然预测的值和实际值肯定是有误差的,所以这个误差-1通过Residual记录下来。
h.264-foreman-1st-frame-i_16x16_0_0_0-mb-up-mb
下面是预测值
h.264-foreman-1st-frame-i_16x16_0_0_0-mb

I_16x16_2_0_0表示预测模型是2(DC),这也是Y分量,同理我们也可以验证。DC是Up的值和Left的值的均值,即((237 * 12 + 229 + 222 + 213 + 206) + (236 * 16)) / (16 * 2),约等于234,这里取整的误差我们认为这些误差是可以接受的,通过CodecVisa我们也可以观察出来,预测值确实为234。
Up和Left的MB如下
h.264-foreman-1st-frame-i_16x16_2_0_0-up-mb
h.264-foreman-1st-frame-i_16x16_2_0_0-left-mb
预测值为
h.264-foreman-1st-frame-i_16x16_2_0_0-mb

另外比如4 x 4的Horizontal Up/Down这些要额外插值计算的预测原理也是如此,只不过稍微复杂点。
这里我们来简单分析下,首先是MB的划分,拆分成8 x 8,里面再拆分成4 x 4,处理的顺序就是先对第1个8 x 8块里面的4个4 x 4块按照光栅顺序处理,然后对第2个8 x 8块进行处理,如下图所示,
h-264-16-x-16-8-x-8-4-x-4-hierarchy
那么对某个具体的4 x 4块预测的时候就好办了,比如我们以Horizontal Up为例子,参照SPEC 8.3.1.2.9 Specification of Intra_4x4_Horizontal_Up prediction mode,截图如下,
4-x-4-intra-prediction-modes-horizontal-up
这就是我们预测的公式,当中p[-1, y]就是我们用来预测的像素,如果没有的话,是不能完成这种模式的预测的。这个预测公式也很容易看懂,x和y就是你要预测的4 x 4块里面每个像素的坐标,所以它们范围只能是0至3。
另外下图我画了比较形象的图来说明,p[-1, y]就代表这里的I,J,K和L,同样图形的坐标里面的值是一样的,图形里面数字一样的表示是用同一个公式计算出来的(公式一样,代入值不一样,所以结果值不同,另外这种内部标记的我没有画完全,只是画出来一个来说明这种情况,就是坐标为[1, 0]和[1, 1]的两个位置),看图,
h-264-horizontal-up-prediction
JM的代码也有比较直观的展示,

  case  HOR_UP_PRED:/* diagonal prediction -22.5 deg to horizontal plane */
    if (!block_available_left)
      printf ("warning: Intra_4x4_Horizontal_Up prediction mode not allowed at mb %d\n",img->current_mb_nr);

	// 一个MB会被拆分成16个4 x 4的块(当然先拆分成4个8 x 8的块),一个4 x 4的块又会包含16个像素,就是这里

	// zHU = x + 2 * y; // x = 0..3, y = 0..3

    img->mpr[0+ioff][0+joff] = (P_I + P_J + 1) / 2; // (p[−1, y + (x >> 1)] + p[−1, y + (x >> 1) + 1] + 1) >> 1 代入 x = 0, y = 0
    img->mpr[1+ioff][0+joff] = (P_I + 2*P_J + P_K + 2) / 4; // (p[−1, y + (x >> 1)] + 2 * p[−1, y + (x >> 1) + 1] + p[−1, y + (x >> 1) + 2] + 2) >> 2 // 代入 x = 1, y = 0 注意right shift
    img->mpr[2+ioff][0+joff] =
    img->mpr[0+ioff][1+joff] = (P_J + P_K + 1) / 2;
    img->mpr[3+ioff][0+joff] =
    img->mpr[1+ioff][1+joff] = (P_J + 2*P_K + P_L + 2) / 4;
    img->mpr[2+ioff][1+joff] =
    img->mpr[0+ioff][2+joff] = (P_K + P_L + 1) / 2;
    img->mpr[3+ioff][1+joff] =
    img->mpr[1+ioff][2+joff] = (P_K + 2*P_L + P_L + 2) / 4;
    img->mpr[3+ioff][2+joff] =
    img->mpr[1+ioff][3+joff] =
    img->mpr[0+ioff][3+joff] =
    img->mpr[2+ioff][2+joff] =
    img->mpr[2+ioff][3+joff] =
    img->mpr[3+ioff][3+joff] = P_L; // p[ −1, 3 ]
    break;

这就是Horizontal Up预测,应该就有了比较透彻的理解。这照相机拍的图在这里显示的orientation不对,直接点过去看大图吧,大图是正确的。

THAVCS当中关于Loop filter的 描述。
A filter is applied to every decoded macroblock to reduce blocking distortion [iv]. The de-
blocking filter is applied after the inverse transform in the encoder before reconstructing and
storing the macroblock for future predictions and in the decoder before reconstructing and
displaying the macroblock.

Intra-coded macroblocks are filtered, but intra prediction (section 6.3) is carried out using unfiltered reconstructed
macroblocks to form the prediction.

CodecVisa软件中Pre-LP表示Loop filter动作之前的数据,IDCT Coefficient表示Inverse DCT Coefficient。

在JM的ldecod和lencod当中会有与预测相关的代码,详见block.c当中名字以intrapred打头的方法,各种预测模式的算法都有。

H.264预测之帧间预测

$
0
0

这是一篇阅读笔记,直接点击图片可以查看清晰大图。

参考资料
The H.264 Advanced Video Compression Standard, Second Edition,以下简称THAVCS
Information technology - Coding of audio-visual objects - Part 10: Advanced Video Coding,以下简称SPEC

CodecVisa
JM
foreman_part_qcif.264 这个是foreman_part_qcif.yuv通过JM 8.6转换来的

http://blog.csdn.net/stpeace/article/details/8115392

帧间预测就是以已经编码好的帧(在display order上可以是当前帧的前面也可以是后面)作为参考帧,确定预测区域,生成预测块,计算出殘差,这些参考帧都存放于Decoded Picture Buffer当中。与帧内预测不同的是,帧间预测是以重建的帧为预测帧的,而帧内预测是一Loop filter之前的帧为预测帧。当前区块和预测区域之间的位移为运动向量(Motion Vector,简写为MV),每个区块有各自的MV,并且MV可以是整数精度,二分之一精度或者四分之一精度(对于4:2:0的视频,C是八分之一精度),这种非整数精度的预测区域都是通过插值算法从参考帧当中计算出来的。

注意,在实际当中MV的单位都是以最小的精度为单位的,比如Y分量的MV单位就是四分之一精度,C分量的MV单位就是八分之一精度,当然这里说的都是4:2:0的视频。

主要过程就是选取参考帧,插值,确定预测区块,确定预测类型,确定运动向量,预测运动向量,编码运动向量差量和殘差,deblocking filter。。。
这里插值计算需要注意的是,先计算二分之一,再计算四分之一,参见THAVCS 6.4.2.1 Generating interpolated sub-pixel samples。

我们来看个实例,先看MV值为整数的,也就是不用插值的。

跟帧内预测所用的码流一样,用CodecVisa打开,选取第二帧(这个码流一共三帧,分别为IPP),选取第4行,第9列的那个MB。
看图inter-prediction-p-slice,
inter-prediction-p-slice
因为这里Y分量MV单位是四分之一精度,所以实际值除以4就是像素偏差。被高亮的块的值向左移动7个像素就刚刚和第一帧当中被高亮位置的值相等,这也就是说当前块是以第一帧所示区块为预测块的,注意帧间预测的参考帧都是重构出来的,都是看Final值,和帧内预测看Pre-LP值不一样,如图inter-prediction-reference-picture,
inter-prediction-reference-picture
这是帧间预测的一个实例。

再来看看非整数精度的情况,MV为(-2.75, -2),垂直方向上是整数,我们不用考虑,现在就看水平方向上。
inter-prediction-p-slice-non-integer-pixel
inter-prediction-reference-picture-non-integer-pixel
如上两张图就分别是当前块和预测块,因为这个MV不是整数的,所以要先插值算出预测块,我们把有需要的数据提取出来,

187    185    187    195 A   199    201    200    200

187    184    191    198 B   199    201    199    200

188    183    174    169 C   183    202    198    200

189    185    166    130 D   132    172    199    202

如上数据就是参考帧重构后的数据,A,B,C和D就是我们要插值算出来的数据,也就是当前块的预测值。

先计算二分之一

Aa = round((1 * 185 - 5 * 187 + 20 * 195 + 20 * 199 - 5 * 201 + 1 * 200) / 32) = 198
Bb = round((1 * 184 - 5 * 191 + 20 * 198 + 20 * 199 - 5 * 201 + 1 * 199) / 32) = 199
Cc = round((1 * 183 - 5 * 174 + 20 * 169 + 20 * 183 - 5 * 202 + 1 * 198) / 32) = 173
Dd = round((1 * 185 - 5 * 166 + 20 * 130 + 20 * 132 - 5 * 172 + 1 * 199) / 32) = 123

然后四分之一

A = round((198 + 195) / 2) = 197
B = round((199 + 198) / 2) = 199
C = round((173 + 169) / 2) = 171
D = round((123 + 130) / 2) = 127

第二列的数据,方法同样
先计算二分之一

Aa + 1 = round((1 * 187 - 5 * 195 + 20 * 199 + 20 * 201 - 5 * 200 + 1 * 200) / 32) = 200
Bb + 1 = round((1 * 191 - 5 * 198 + 20 * 199 + 20 * 201 - 5 * 199 + 1 * 200) / 32) = 200
Cc + 1 = round((1 * 174 - 5 * 169 + 20 * 183 + 20 * 202 - 5 * 198 + 1 * 200) / 32) = 195
Dd + 1 = round((1 * 166 - 5 * 130 + 20 * 132 + 20 * 172 - 5 * 199 + 1 * 202) / 32) = 150

然后四分之一

A = round((200 + 199) / 2) = 200
B = round((200 + 199) / 2) = 200
C = round((195 + 183) / 2) = 189
D = round((150 + 132) / 2) = 141

后面的就不再罗列了,从结果来看,我们这里预测的结果

197    200    ....
199    200    ....
171    189    ....
127    141    ....

和CodecVisa有些许出入,但是变化趋势相同的,所以这个实验的基本目的达到了。

C/CPP中的坑

$
0
0

记录C/CPP当中一些隐晦的问题,并非著名的C Traps and Pitfalls,虽然有可能包含一些相同的点。

1、类型退化(隐式转换)问题

#include <stdio.h>

#define SIZEOF(A) \
	sizeof(A) / sizeof(A[0])

inline static int sizeOfCharArray(char a[])
{
	return sizeof(a) / sizeof(a[0]); // type casting by default
}

int main(int argc, char **argv)
{
	char a[10];
	a[0] = 5;
	a[9] = 8;

	void *p = &a; // do it explicitly

	printf("sizeof char array %d %lu %lu\n", sizeOfCharArray(a), sizeof((char*) p), SIZEOF(a));

	return 0;
}

注意这段程序当中sizeOfCharArray方法,其实在很多情况都会有隐式转换,但是和sizeof一起用的时候要注意。

2、多层循环,效率问题

http://rednaxelafx.iteye.com/blog/352730


汉诺塔游戏

$
0
0

前天在一次面试中,面试官问到我汉诺塔(Towers of Hanoi)的问题,当时只知道是递归,知道手动玩游戏怎么玩,写程序还真的忘记了。大学我记得是有写过这样的作业,还有八皇后等等,不过真的都还给老师了,哈哈哈!

然后回家看了下,

http://www.cs.cmu.edu/~cburch/survey/recurse/hanoiimpl.html

http://www.python-course.eu/towers_of_hanoi.php

汉诺塔的介绍参见http://en.wikipedia.org/wiki/Tower_of_Hanoi等等

程序如下,

#include <stdio.h>

void move(char src, char dest)
{
	printf("\nMove the top plate of %c to %c", src, dest);
}

void hanoi(int n, char a, char b, char c)
{
	if (n == 1) { // 递归结束
		move(a, c); // 最小的那个盘子
	} else {
		hanoi(n - 1, a, c, b); // step 1,把所有小于最大的盘子移动到临时的柱子上(可以借助目的柱子)
		move(a, c); // step 2,把最大的盘子移动到目的柱子上
		hanoi(n - 1, b, a, c); // step 3,把临时的柱子上的盘子移动到目的柱子上(可以借助原始柱子),和step 1的方式一模一样

							// step 1和3都会有递归产生
	}
}

int main()
{
	int n;
	printf("\nPlz input number of the plates:");
	scanf("%d", &n);
	printf("\nMoving %d plates from A to C:", n);

	hanoi(n, 'A', 'B', 'C');

	printf("\nDone!\n");
}

如果你能看懂上面的注释,很好。如果你看不懂,也没关系,现在我们来试着详细点解释这个问题。
我们先来玩这个游戏,如图(点击图片看正常大图),
Towers of Hanoi
你会发现盘子的数量和最终要花费的步数是有关系的,为2^n - 1,也就是说只有1个盘子的时候需要1步,2个盘子的时候需要3步,3个盘子的时候需要7步,以此直到天荒地老。。。

所以这种思路我们是不是可以采用递归那完成呢?
比如3个盘子的时候,我们先移动上面的2个盘子(需要3步),再移动最大的1个盘子(需要1步),然后再移动那2个盘子到最大的盘子上面(需要3步),加起来一共就是7步,刚刚好。
并且2个盘子也可以同理拆分,最终会变成1个盘子的情况,1个盘子的情况很好解决,就1步,别且这也就是边界情况。

看起来这样是可以,再回头来看看程序,
step 1 ~ 3是不是很清晰了,并且step 1和3自己又会有递归产生,继续拆分,直到最后都是1个盘子的时候,递归结束。

如果不关心内部细节是不是就这样完美结束了呢?确实,如果你不关心内部细节,这样已经让人很容易的理解这个问题。但是总归会有一部分人会继续深挖。
现在我们以3个盘子为例,以程序执行的角度来看,

hanoi(3, 'A', 'B', 'C')
{
	hanoi(2, 'A', 'C', 'B');
		hanoi(1, 'A', 'B', 'C')
			move('A', 'C')
		move('A', 'B')
		hanoi(1, 'C', 'A', 'B')
			move('C', 'B')
	move('A', 'C');
	hanoi(2, 'B', 'A', 'C');
		hanoi(1, 'B', 'C', 'A')
			move('B', 'A')
		move('B', 'C')
		hanoi(1, 'A', 'B', 'C')
			move('A', 'C')
}

好像也没什么好写的,有机会看看非递归的方式来实现。

P.S.
递归有风险,使用需谨慎!

迁移博客到Digital Ocean

$
0
0

搜了下据说性价比还可以的VPS,似乎我在上海ping值很高,用用看吧(可以按小时付费)。

注册账号,创建VPS,拿到root用户

ssh root@162.243.117.95

创建常用账户

ssh guohai@162.243.117.95

拿到之后当然先装些基础的软件,比如FTP服务,SSL等等,这个看自己的爱好。
摸出我当年做各种MIS的经验,什么Nginx/MySQL/PHP,不过PHP我之前没有弄过,照着网络上简单的搞搞。

[root@Knight-on-the-Cloud ~]# yum -y install vsftpd
参照

http://my.oschina.net/u/130017/blog/15229

基础配置

local_enable=YES
ascii_upload_enable=YES
ascii_download_enable=YES
write_enable=YES

然后就是MySQL
[root@Knight-on-the-Cloud log]# yum -y install mysql-server

[root@Knight-on-the-Cloud log]# service mysqld start
Initializing MySQL database: WARNING: The host 'Knight-on-the-Cloud' could not be looked up with resolveip.
This probably means that your libc libraries are not 100 % compatible
with this binary MySQL version. The MySQL daemon, mysqld, should work
normally with the exception that host name resolving will not work.
This means that you should use IP addresses instead of hostnames
when specifying MySQL privileges !
Installing MySQL system tables...
OK
Filling help tables...
OK

To start mysqld at boot time you have to copy
support-files/mysql.server to the right place for your system

PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !
To do so, start the server, then issue the following commands:

/usr/bin/mysqladmin -u root password 'new-password'
/usr/bin/mysqladmin -u root -h Knight-on-the-Cloud password 'new-password'

Alternatively you can run:
/usr/bin/mysql_secure_installation

which will also give you the option of removing the test
databases and anonymous user created by default. This is
strongly recommended for production servers.

See the manual for more instructions.

You can start the MySQL daemon with:
cd /usr ; /usr/bin/mysqld_safe &

You can test the MySQL daemon with mysql-test-run.pl
cd /usr/mysql-test ; perl mysql-test-run.pl

Please report any problems with the /usr/bin/mysqlbug script!

[ OK ]
Starting mysqld: [ OK ]

这样装好之后就记住你MySQL的root密码啦,记得所有都是最小权限原则,不用的就不需要开。

移动MySQL数据文件位置,当然先得停止MySQL服务。
这几个命令都是在OS的root权限下进行的。
mkdir -p /usr/local/mysql
cp -afir /var/lib/mysql/* /usr/local/mysql

vim /etc/my.cnf

[mysqld]
datadir=/usr/local/mysql
socket=/usr/local/mysql/mysql.sock
default-character-set=utf8
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

[mysql]
default-character-set=utf8

vim /etc/init.d/mysqld
datadir=/usr/local/mysql

启动MySQL,并登录试试。
mysql -h 127.0.0.1 -P 3306 -u root -p
或者用
mysql -u root -p
来登录

最后还是创建一个软链接,主要是后面PHP程序连过来的时候是找的默认这个地方(/var/lib/mysql/mysql.sock)
[root@Knight-on-the-Cloud mysql]# mkdir -p /var/lib/mysql/
[root@Knight-on-the-Cloud mysql]# ln -s /usr/local/mysql/mysql.sock /var/lib/mysql/mysql.sock

如果数据库能启动,看看/var/log/mysqld.log里面日志都正常的话,这步就应该好了。

安装Nginx

https://www.digitalocean.com/community/articles/how-to-compile-nginx-from-source-on-an-centos-6-4-x64-vps

编译参数如下

./configure \
--user=nginx                          \
--group=nginx                         \
--prefix=/etc/nginx                   \
--sbin-path=/usr/sbin/nginx           \
--conf-path=/etc/nginx/nginx.conf     \
--pid-path=/var/run/nginx.pid         \
--lock-path=/var/run/nginx.lock       \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module        \
--with-http_stub_status_module        \
--with-http_ssl_module                \
--with-pcre                           \
--with-file-aio                       \
--with-http_realip_module             \
--without-http_scgi_module            \
--without-http_uwsgi_module           \
--without-http_fastcgi_module

注意,如果你弄好这些启动的话,发现
nginx: [emerg] unknown directive "fastcgi_pass"
nginx不要带这个参数--without-http_fastcgi_module编译,这样就表示Nginx集成了fastCGI的功能,也就不需要使用spawn-fcgi等等。

配置/etc/nginx/nginx.conf
types_hash_bucket_size 64;
server_names_hash_bucket_size 128;

加入
include /etc/nginx/conf.d/*.conf;
到/etc/nginx/nginx.conf

安装PHP

https://www.digitalocean.com/community/articles/how-to-install-linux-nginx-mysql-php-lemp-stack-on-centos-6

如果没有启用Nginx或者PHP的fastCGI,就只能安装

http://www.lighttpd.net/download/spawn-fcgi-1.6.3.tar.gz

了,因为我们在编译Nginx的时候有http_fastcgi_module,所以就不需要这个了

Nginx出现403,
原因http://www.linuxidc.com/Linux/2013-06/85625.htm

vim /etc/nginx/nginx.conf
user guohai;

root 18137 0.0 0.2 44552 1092 ? Ss 13:30 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
guohai 18139 0.0 0.3 44956 1708 ? S 13:30 0:00 nginx: worker process
guohai 18140 0.0 0.3 44956 1708 ? S 13:30 0:00 nginx: worker process
guohai 18141 0.0 0.3 44956 1680 ? S 13:30 0:00 nginx: worker process
guohai 18142 0.0 0.3 44956 1692 ? S 13:30 0:00 nginx: worker process

访问目录权限
[guohai@Knight-on-the-Cloud html]$ ls -l
total 4
drwxrwxr-- 2 guohai guohai 4096 Nov 27 11:07 guoh.org

[guohai@Knight-on-the-Cloud guoh.org]$ ls -l
total 8
-rw-rw-r-- 1 guohai guohai 0 Nov 27 13:37 hello.txt
-rw-rw-r-- 1 guohai guohai 612 Nov 27 11:33 index.html
-rw-rw-r-- 1 guohai guohai 617 Nov 27 11:05 info.php

PHP页面出现,
404, No input file specified.
vim /etc/php-fpm.d/www.conf
Unix user/group of processes里面用户和组控制的和所需要访问文件属于同一个用户和组就好,我这里都改成guohai。

root 18409 0.0 0.7 125452 3952 ? Ss 15:09 0:00 php-fpm: master process (/etc/php-fpm.conf)
guohai 18410 0.0 1.0 126088 5208 ? S 15:09 0:00 php-fpm: pool www
guohai 18411 0.0 1.0 125972 5216 ? S 15:09 0:00 php-fpm: pool www
guohai 18412 0.0 0.8 125972 4136 ? S 15:09 0:00 php-fpm: pool www
guohai 18413 0.0 0.8 125452 4124 ? S 15:09 0:00 php-fpm: pool www
guohai 18414 0.0 1.0 126088 5208 ? S 15:09 0:00 php-fpm: pool www

所以这两个诡异的问题都是权限问题

也就是我们这里Nginx和PHP的运行用户都是guohai,文件所属也都是guohai,这样就不会出任何问题了(Nginx或者PHP的master process都是运行在daemon当中,所以这里是root),当然可能正式服务器上应该部署在www这种权限比较少的用户下面。

我这里是迁移工作,所以数据库和程序文件我都有导入出来,现在只需要导入数据库,把文件放到指定的目录就好。如果是全新安装的话,只要创建好数据库和用户就好,安装WP的时候会自动生成数据库。
创建数据库和用户

CREATE DATABASE wp_db;
CREATE USER wp_user@localhost;
SET PASSWORD FOR wp_user@localhost= PASSWORD("YOUR_STRONG_PASSWORD");
GRANT ALL PRIVILEGES ON wp_db.* TO wp_user@localhost IDENTIFIED BY 'YOUR_STRONG_PASSWORD';
FLUSH PRIVILEGES;

当然你如果熟悉MySQL的话,可以细分权限,给够就行了。

https://www.digitalocean.com/community/articles/how-to-install-wordpress-with-nginx-on-centos-6--2

WordPress在Nginx上开启固定链接(permalinks),参见的是http://blog.dighost.me/archives/3233.html,网络上很多方法都不成功,不知道到底是对视错,我的是WP放在子目录(lifelog)下面,所以

    location / {
        index index.php  index.html index.htm;
        try_files $uri $uri/ /index.php?$args;
#       try_files and rewrite, which is better?
#        if (-f $request_filename/index.html) {
#            rewrite (.*) $1/index.html break;
#        }
#        if (-f $request_filename/index.php) {
#            rewrite (.*) $1/index.php;
#        }
#        if (!-f $request_filename) {
#            rewrite (.*) /index.php;
#        }
    }

    location /lifelog/ {
        index index.php  index.html index.htm;
        try_files $uri $uri/ /lifelog/index.php?$args;
    }

也就是我只修改了location /lifelog/的内容,并且index后面有这么多,部分人只放了index.php,但是我这样就会出现404,如果写全就能工作,所以。。。

所有东西都弄好之后,然后可以隐藏掉Nginx/PHP版本号,避免软件漏洞出现后,攻击者很容易知道你的系统软件版本,然后直接拿下你的机器,不过我这台机器应该没有人感兴趣。
参见http://wangye.org/blog/archives/352/
分别在/etc/nginx/nginx.conf增加
http {
# ...省略一些配置
server_tokens off;
}

在/etc/php.ini关闭expose_php,即修改为
expose_php = Off
或者你自己编译源码,尽量隐藏掉你不想让别人看到的信息。

P.S.
运行了几个小时,发现有时候还是会有404,先用用看有没有什么比较严重的问题,备份很重要,有空来写几个脚本去定时导出和打包数据库和文件。
需要注册的同学可以使用https://www.digitalocean.com/?refcode=7340d6d347a6这个优惠码,你好我也好,哈哈哈 /偷笑

跑了会儿就觉得站点反应慢,看了下
top发现CPU很空,Memory几乎满掉了
ps -A --sort -rss -o comm,pmem,pcpu | uniq -c | head -15
发现php-fpm占了很多内存
ps aux | grep php-fpm
网上搜了下,遇到php-fpm开的多的人很多,而每个php-fpm进程大约占用20M左右的内存,所以内存很快就会耗光了

http://www.perfgeeks.com/?p=599

http://www.ha97.com/4339.html

这两篇博客解释了php-fpm的工作方式,我这里是动态的,然后我这里VPS的内存比较小,而max_spare_servers默认是35个,所以就会耗非常多的内存,于是我尝试将这个值改小。
vim /etc/php-fpm.d/www.conf
修改pm.max_spare_servers
再跑跑看。

P.P.S. 难道为了搞个VPS搭个小站,还要逼我学习如何调优Nginx/PHP/MySQL?突然发现还是我那个40人民币/年的空间比较好,ping值也低,也没有这么多事,可惜它经常不出声响的就处于维护状态,让人比较头疼。用了这个VPS,现在如果坏了得自己修了。。。

P.P.P.S 发现这事停不下来了
一些Nginx简单的配置
vim /etc/nginx/nginx.conf

Nginx上开启gzip选项

    gzip  on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_types text/plain application/x-javascript text/css application/xml;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";

可以用curl命令测试下是否设置生效

curl -I guoh.org/lifelog/ -H Accept-Encoding:gzip,defalte // 指定Head接收编码信息
curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -I guoh.org/lifelog/ -H Accept-Encoding:gzip,defalte // 指定代理为某种浏览器,可以用任意值来"欺骗"服务器
curl -A "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" -I guoh.org/lifelog/ -H Accept-Encoding:gzip,defalte

配置静态文件超时时间

    location ~* .(ico|gif|bmp|jpg|jpeg|png|swf|js|css|mp3) {
        expires 30d;
    }

Nginx Proxy Cache如果有需要的话,再来研究。
http段里面添加

proxy_connect_timeout 10;
proxy_read_timeout 180;
proxy_send_timeout 5;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
proxy_temp_path /tmp/temp_dir;
proxy_cache_path /tmp/cache levels=1:2 keys_zone=cache_one:100m inactive=1d max_size=10g;

server段里面添加

location ~ .*\.(gif|jpg|png|css|js)(.*) {
     proxy_pass http://appserver ;
     proxy_redirect off;
     proxy_set_header Host $host;
     proxy_cache cache_one;
     proxy_cache_valid 200 302 24h;
     proxy_cache_valid 301 30d;
     proxy_cache_valid any 5m;
     expires 90d;
}

WP插件有关
顺手把SyntaxHighlighter做了些调整,选用第三版,调整了下它的隔行变色以及高亮行颜色
vim lifelog/wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/styles/shThemeDefault.css

.syntaxhighlighter .line.alt1 {
  background-color: white !important;
}
.syntaxhighlighter .line.alt2 {
  background-color: #EEE !important;
}
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
  background-color: #FFFF00 !important;
}

Python连接MySQL数据库

$
0
0

为了写个简单的备份程序,我决定使用Python来实现,几年前有看过点Python,今天就来试试看。通常我们连接数据库会用到对应的连接API,比如Java的JDBC(Java_Database_Connectivity‎),顶多中间增加个连接池之类的,因为我们这里很简单,所以只需要一个类似的API,我们这里用MySQL-python来完成。先安装这个东西,我采用1.2.3版本,当然我这里宿主机器是CentOS。

[guohai@Knight-on-the-Cloud installation]$ wget http://sourceforge.net/projects/mysql-python/files/mysql-python/1.2.3/MySQL-python-1.2.3.tar.gz/download
[guohai@Knight-on-the-Cloud installation]$ tar xvf MySQL-python-1.2.3.tar.gz
[guohai@Knight-on-the-Cloud installation]$ cd MySQL-python-1.2.3

vim site.cfg

# The path to mysql_config.
# Only use this if mysql_config is not on your PATH, or you have some weird
# setup that requires it.
mysql_config = /usr/bin/mysql_config

正如这上面所说,之前我安装MySQL有改动默认位置,所以这里要单独指定下。

[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python setup.py build

if errors("no setuptools") showing

cd ..
wget https://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c10-py2.6.egg --no-check-certificate
sh setuptools-0.6c10-py2.6.egg

然后

cd MySQL-python-1.2.3

[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python setup.py build

if errors("Python.h: No such file or directory") showing

[root@Knight-on-the-Cloud installation]# yum -y install python-devel

继续

[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python setup.py build
running build
running build_py
copying MySQLdb/release.py -> build/lib.linux-x86_64-2.6/MySQLdb
running build_ext
building '_mysql' extension
gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -Dversion_info=(1,2,3,'final',0) -D__version__=1.2.3 -I/usr/include/mysql -I/usr/include/python2.6 -c _mysql.c -o build/temp.linux-x86_64-2.6/_mysql.o -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fwrapv -fPIC -DUNIV_LINUX -DUNIV_LINUX
_mysql.c:36:23: error: my_config.h: No such file or directory
_mysql.c:38:19: error: mysql.h: No such file or directory
_mysql.c:39:26: error: mysqld_error.h: No such file or directory
_mysql.c:40:20: error: errmsg.h: No such file or directory
[root@Knight-on-the-Cloud include]# yum -y install mysql-devel

[root@Knight-on-the-Cloud mysql]# pwd
/usr/include/mysql
[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python setup.py build
running build
running build_py
copying MySQLdb/release.py -> build/lib.linux-x86_64-2.6/MySQLdb
running build_ext
building '_mysql' extension
gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -Dversion_info=(1,2,3,'final',0) -D__version__=1.2.3 -I/usr/include/mysql -I/usr/include/python2.6 -c _mysql.c -o build/temp.linux-x86_64-2.6/_mysql.o -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fwrapv -fPIC -DUNIV_LINUX -DUNIV_LINUX
In file included from /usr/include/mysql/my_config.h:14,
                 from _mysql.c:36:
/usr/include/mysql/my_config_x86_64.h:1082:1: warning: "HAVE_WCSCOLL" redefined
In file included from /usr/include/python2.6/pyconfig.h:6,
                 from /usr/include/python2.6/Python.h:8,
                 from pymemcompat.h:10,
                 from _mysql.c:29:
/usr/include/python2.6/pyconfig-64.h:808:1: warning: this is the location of the previous definition
gcc -pthread -shared build/temp.linux-x86_64-2.6/_mysql.o -L/usr/lib64/mysql -L/usr/lib64 -lmysqlclient_r -lz -lpthread -lcrypt -lnsl -lm -lpthread -lssl -lcrypto -lpython2.6 -o build/lib.linux-x86_64-2.6/_mysql.so

编译好了就安装

[root@Knight-on-the-Cloud MySQL-python-1.2.3]# python setup.py install
running install
running bdist_egg
running egg_info
writing MySQL_python.egg-info/PKG-INFO
writing top-level names to MySQL_python.egg-info/top_level.txt
writing dependency_links to MySQL_python.egg-info/dependency_links.txt
reading manifest file 'MySQL_python.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
warning: no files found matching 'MANIFEST'
warning: no files found matching 'ChangeLog'
warning: no files found matching 'GPL'
writing manifest file 'MySQL_python.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-x86_64/egg
running install_lib
running build_py
copying MySQLdb/release.py -> build/lib.linux-x86_64-2.6/MySQLdb
running build_ext
creating build/bdist.linux-x86_64
creating build/bdist.linux-x86_64/egg
copying build/lib.linux-x86_64-2.6/_mysql.so -> build/bdist.linux-x86_64/egg
copying build/lib.linux-x86_64-2.6/_mysql_exceptions.py -> build/bdist.linux-x86_64/egg
creating build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/__init__.py -> build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/cursors.py -> build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/connections.py -> build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/times.py -> build/bdist.linux-x86_64/egg/MySQLdb
copying build/lib.linux-x86_64-2.6/MySQLdb/release.py -> build/bdist.linux-x86_64/egg/MySQLdb
creating build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/REFRESH.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/CLIENT.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/FIELD_TYPE.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/FLAG.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/__init__.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/CR.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/constants/ER.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
copying build/lib.linux-x86_64-2.6/MySQLdb/converters.py -> build/bdist.linux-x86_64/egg/MySQLdb
byte-compiling build/bdist.linux-x86_64/egg/_mysql_exceptions.py to _mysql_exceptions.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/cursors.py to cursors.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/connections.py to connections.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/times.py to times.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/release.py to release.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/REFRESH.py to REFRESH.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/CLIENT.py to CLIENT.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/FIELD_TYPE.py to FIELD_TYPE.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/FLAG.py to FLAG.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/CR.py to CR.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/ER.py to ER.pyc
byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/converters.py to converters.pyc
creating stub loader for _mysql.so
byte-compiling build/bdist.linux-x86_64/egg/_mysql.py to _mysql.pyc
creating build/bdist.linux-x86_64/egg/EGG-INFO
copying MySQL_python.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO
copying MySQL_python.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying MySQL_python.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying MySQL_python.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
writing build/bdist.linux-x86_64/egg/EGG-INFO/native_libs.txt
zip_safe flag not set; analyzing archive contents...
creating dist
creating 'dist/MySQL_python-1.2.3-py2.6-linux-x86_64.egg' and adding 'build/bdist.linux-x86_64/egg' to it
removing 'build/bdist.linux-x86_64/egg' (and everything under it)
Processing MySQL_python-1.2.3-py2.6-linux-x86_64.egg
Copying MySQL_python-1.2.3-py2.6-linux-x86_64.egg to /usr/lib64/python2.6/site-packages
Adding MySQL-python 1.2.3 to easy-install.pth file

Installed /usr/lib64/python2.6/site-packages/MySQL_python-1.2.3-py2.6-linux-x86_64.egg
Processing dependencies for MySQL-python==1.2.3
Finished processing dependencies for MySQL-python==1.2.3

接着再来试下

[guohai@Knight-on-the-Cloud MySQL-python-1.2.3]$ python
Python 2.6.6 (r266:84292, Jul 10 2013, 22:48:45)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb
/usr/lib64/python2.6/site-packages/MySQL_python-1.2.3-py2.6-linux-x86_64.egg/_mysql.py:3: UserWarning: Module _mysql was already imported from /usr/lib64/python2.6/site-packages/MySQL_python-1.2.3-py2.6-linux-x86_64.egg/_mysql.pyc, but /home/guohai/apps/installation/MySQL-python-1.2.3 is being added to sys.path

上面这些UserWarning是说MySQL模块已经引入了,但是你在的目录又被加入到sys.path,也就是重复引入。这个时候你只要跳出我们刚刚编译模块的目录就好了。
一切都正常之后我们来写个简单的程序试试看。

[guohai@Knight-on-the-Cloud npc]$ python
Python 2.6.6 (r266:84292, Jul 10 2013, 22:48:45)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb

>>> help(MySQLdb) // 不懂的话就可以这样查询

>>> conn = MySQLdb.connect('localhost', 'wp_user', 'wp_passwd', 'wp_db')
>>> cur = conn.cursor()
>>> cur.execute('select user_login, user_registered from wp_users')
1L
>>> rst = cur.fetchall()
>>> print rst
(('admin', datetime.datetime(2011, 3, 19, 0, 8, 9)),)
>>> cur.close()
>>> conn.close()

与我们通过

[guohai@Knight-on-the-Cloud npc]# mysql -h localhost -u wp_user -p

查询出来的一样

mysql> select * from wp_users \G
*************************** 1. row ***************************
                 ID: 1
         user_login: admin
          user_pass: #CLASSIFIED#
      user_nicename: #CLASSIFIED#
         user_email: #CLASSIFIED#
           user_url: #CLASSIFIED#
    user_registered: 2011-03-19 00:08:09
user_activation_key: #CLASSIFIED#
        user_status: #CLASSIFIED#
       display_name: #CLASSIFIED#
1 row in set (0.00 sec)

也就是说我们简单的连接数据库成功了,到此基础环境算是搭建好了。

另外简单写了个备份程序(https://github.com/guohai/my-conf/blob/master/wp_backup_npc.py),待完善。。。

小结二零一三

$
0
0

似乎已经过了年终小结的时间了,不过迟点就迟点吧,今年可以典型的分为上半年和下半年,上半年在为公司加班(已经是前东家了),下半年在为自己加班,还是有点忙,不过也没有什么好看的结果,人生很多时候是努力了不一定有明显的结果的。去年的愿望有实现了部分,乱七八糟的读了一些书,C/C++,还有部分多媒体知识有了些进步,有些东西看起来比较复杂和庞大,不过当你花了很多时间在上面,并且突然理解的时候,这是最开心的,比通常在公司里实现了一个又一个功能,解了一个又一个bug的感觉要好太多,当然我知道工作只是工作,如果你的工作不是你的兴趣所在,那你的路就是把它做好或者换一份工作,或者如果你无法换工作的时候就只是做好它然后自己做自己爱好的事情,老板给你的任务太重你需要表达出自己的状况,要不然很大的可能就是你被更多的工作包围着,这当然不是教你偷懒,万事都有一个度的问题。你若热爱它,怎么努力都不过分,若不热爱,就要努力去寻找到自己的胡萝卜。。。当然一些事情也没有能做的很好,比如多回去看看爸妈,比如多学习深入点的多媒体/信息论的知识,这也成为了2014的目标。具体点来说今年可能会更多的关注在语音这方面,因为刚刚加入了一家这方面的创业公司,估计还是一样的会比较忙碌,不过还是尽量不要让自己完全被工作给吞噬了。。。2014还是力争多读点书,语音方面理解AudioFlinger,至少熟悉一种CODEC。还有一个个人方面的愿望就是能有一个可以共度一生的人,在一个充满阳光的下午,两个人坐一起,一个人在写代码,一个人在看书,或者有时间两个人出去吃喝玩乐,平平淡淡,普普通通就好,不知道这是不是一种奢求!

Building Android apps with Jenkins CI

$
0
0

在前东家,工程相关的都有专门的组来做,比如自动化的代码审查,编译,发布,测试,缺陷追踪等等系统。。。甚至当时就有人说就XXX的很多系统,即使司龄很大的员工都不一定都能使用的很熟练,因为实在是太多了。。。相反的是现在都没有,万事都需要自己动手,不过也还好,可以挑选些真的是非常有帮助的自动化系统来帮助我们提高工作效率(比如之前我一直都是不大记住写周报,其实我觉得那应该是小时报,不过还好,我当时的老大和部门经理对这个要求没有那么严格,我也不是偷懒的员工,所以基本是马马虎虎过了,但是我还是比较喜欢例如某些任务管理系统,用任务管理系统主要是防止自己忘记,一些大任务可以拆分成小任务,并且标记完成状况,或者是你在任务上撰写出你自己的意见/建议和老大进行沟通),今天就以自动化编译系统为起点来逐步搭建/定制出一个比较理想的持续集成系统。。。当然这是一个长期的任务,不是说它非常难,只是自己时间也不是特别多,会先挑些目前比较重要的东西来加入进来(building,lint,findbugs,monkey)。。。
今天先说编译系统,而且先是看基于Ant的,假设源码是放在GitHub上,比如https://github.com/guohai/and-expandable-listview/这个项目,我希望我的系统在每隔一定时间或者每次代码提交之后自己启动一次编译,第一这可以排错,防止开发人员不小心漏提交代码,或者merge代码的时候出错,尽早的发现这类比较低级的错误,编译系统编译失败会立刻邮件通知你,而不是你在本地编译测试了很多遍,信心满满的把代码提交(当然有人说会有人工代码审查,但是人工也不一定能发现所有错误,特别是编译错误),回家睡觉了,另外一个时区的同事刚开始新的一天,检出你的代码,发现根本编译不通过,那么他是该打你的电话叫醒你修改代码呢?还是等你第二天来修改呢?明显他两样都不想,所以最好是你保证自己提交的代码都是至少可以编译通过的(会有人说这么简单的事情会做不到吗?事实是当你很多人协同工作的时候,这个事情确实是有可能发生,很多次在XXX公司经历过一两天编译系统无法出一个可以通过的版本,当然这不是在黑前东家,只是事情确实有,而且公司也在逐步改用好一点的编译方式减少这种一个编译错误导致整个系统都无法编译出ROM的窘境);第二这个可以利用一些工具直接将编译的成果推送到自动化测试的服务里面完成基础的自动化测试,这样岂不是很好,减少些不必要的人工操作;第三有权限的人可以随时下载一个他需要的版本程序来安装运行,而不需要让你给他邮件发一个版本或者他自己安装编译环境,检出代码来完成编译。可能还有很多理由来需要这样一个系统,不过这里已经够了。。。
Jenkins的安装,基本使用就不说了,具体查看https://wiki.jenkins-ci.org/display/JENKINS/Use+Jenkins上面,我这里主要安装了一个GitHub插件,在Manage Jenkins->Manage Plugins当中可以很方便的完成,因为我本地都有Android SDK, Ant, Java等等一些基础环境,而且这些都已经在PATH当中,所以集成起来就很简单。然后就是创建任务, Jenkins当中称为job,然后就是配置该job,比如GitHub项目位置,仓库地址,keystore for release build,编译预处理,归档编译产物,以及触发编译条件,如下图:
Screen Shot 2014-01-27 at 12.00.47 AM
Screen Shot 2014-01-27 at 12.01.53 AM
Screen Shot 2014-01-27 at 12.14.36 AM
Screen Shot 2014-01-27 at 12.15.05 AM
Screen Shot 2014-01-27 at 12.34.11 AM
Screen Shot 2014-01-27 at 12.43.14 AM
这样就基本可以搭建出一个自动化的编译系统了,后面有机会来研究下基于Gradle的,毕竟这才是Google目前主导的方向。
当然你可以根据自己的需要调节更改配置来达到想要自己的目的,比如GitHub有提交就触发编译,只归档特定名字的文件等等,是否删除原有归档,如果新的版本有成功编译出来的话,等等可能还有更多的技巧。

洗完个澡,顺便试了下Gradle的,你可以在Jenkins当中下载Gradle插件,也可以不用专门下载,自己写个简单的脚本完成,比如我这里就是:
Screen Shot 2014-02-06 at 12.25.49 AM
而且也只有上述这一段不一样,其他都跟Ant的基本类似,不过生成需要归档的apk的路径可能需要改改,这里有个硬编码的ANDROID_HOME,目前没有发现比较好的解决方法,如果您知道如何解决,不吝赐教。在Ant版本中,我们sdk.dir是通过android update project生成的,但是在Gradle的项目当中似乎无法生成,没有SDK路径就会编译出错,比如:

* Where:
Build file '/Users/guohai/.jenkins/jobs/Gradle-Proj-Test/workspace/xxx/build.gradle' line: 9

* What went wrong:
A problem occurred evaluating project ':beckon'.
> SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.
于是就先硬编码这个ANDROID_HOME变量先跳过这一问题,有空再来研究看看。
1
export ANDROID_HOME=/Users/guohai/Dev/android-sdk-macosx
chmod +x ./gradlew
./gradlew clean assembleDefaultFlavorDebug

当然这gradlew后面跟的task可以自己调整,比如debug版本或者release版本。

Tips about Android Studio

$
0
0

还是开一篇记录Android Studio有关的各种诡异问题。
首先感谢一下,一直以Preview状态出现的AS最近终于是Beta了,普天同庆!
AS有好也有不好,但是感觉就是用了它就回不去Eclipse了。

之前基本在版本升级的时候都会或多或少出现点问题,有的坑了很久,记录分享下,避免在这上面浪费时间!

1. 一直提示refreshing/configure project,很长时间都不会结束。
经过观察这个是在现在一些依赖包,有800多M,网速慢的话估计很难等到下载完成的时候。有个解决办法就是在Preferences当中选择Gradle为Offline work模式。
当然也可以全局配置Offline work,打开$HOME/.gradle/init.gradle,如果没有该文件就创建一个,然后在里面添加

allprojects {
    repositories {
        .......
    }

    gradle.startParameter.setOffline(true)
}

主要就是这句gradle.startParameter.setOffline(true)啦,不是很明白的可以去网络上搜索了解下,
http://www.gradle.org/docs/current/userguide/init_scripts.html
http://www.gradle.org/docs/current/javadoc/org/gradle/StartParameter.html
如果发现创建项目之后,已经处于这种卡住的状态,可以断开网络链接,一会儿这种卡住状态就会消失了。

2. 2014-07-01 10:24:55,919 [1292862] INFO - .project.GradleProjectImporter - The project is using an unsupported version of the Android Gradle plug-in (0.11.2)
鼠标移动到build.gradle当中的classpath值上面,根据提示修改就可以

    dependencies {
        classpath 'com.android.tools.build:gradle:0.11.+'
    }

然后执行gradlew clean assembleDefaultFlavor或者直接clean build工程,应该就可以解决。

3. 还有个东西叫做代理,关键的时候可以用上。

Parcelable encounteredClassNotFoundException reading a Serializable object

$
0
0

记录下,这个问题一直无法知道合理的原因

1065 07-09 22:25:29.927 670 918 E AmStub : java.lang.RuntimeException: Parcelable encounteredClassNotFoundException reading a Serializable object (name = xx.oo.MySerializableObject)
1066 07-09 22:25:29.927 670 918 E AmStub : at android.os.Parcel.readSerializable(Parcel.java:2148)
1067 07-09 22:25:29.927 670 918 E AmStub : at android.os.Parcel.readValue(Parcel.java:2016)
1068 07-09 22:25:29.927 670 918 E AmStub : at android.os.Parcel.readMapInternal(Parcel.java:2226)
1069 07-09 22:25:29.927 670 918 E AmStub : at android.os.Bundle.unparcel(Bundle.java:223)
1070 07-09 22:25:29.927 670 918 E AmStub : at android.os.Bundle.containsKey(Bundle.java:271)
1071 07-09 22:25:29.927 670 918 E AmStub : at android.content.Intent.hasExtra(Intent.java:4414)
1072 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.c.a(Unknown Source)
1073 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.AmSmartShowStub.checkStartActivity(Unknown Source)
1074 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.ActivityManagerService.checkStartActivity(ActivityManagerService.java:3015)
1075 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3224)
1076 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3213)
1077 07-09 22:25:29.927 670 918 E AmStub : at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:144)
1078 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1968)
1079 07-09 22:25:29.927 670 918 E AmStub : at android.os.Binder.execTransact(Binder.java:351)
1080 07-09 22:25:29.927 670 918 E AmStub : at dalvik.system.NativeStart.run(Native Method)
1081 07-09 22:25:29.927 670 918 E AmStub : Caused by: java.lang.ClassNotFoundException: xx.oo.MySerializableObject
1082 07-09 22:25:29.927 670 918 E AmStub : at java.lang.Class.classForName(Native Method)
1083 07-09 22:25:29.927 670 918 E AmStub : at java.lang.Class.forName(Class.java:217)
1084 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2279)
1085 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1638)
1084 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2279)
1085 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1638)
1086 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:658)
1087 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1781)
1088 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:762)
1089 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1981)
1090 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1938)
1091 07-09 22:25:29.927 670 918 E AmStub : at android.os.Parcel.readSerializable(Parcel.java:2142)
1092 07-09 22:25:29.927 670 918 E AmStub : ... 14 more
1093 07-09 22:25:29.927 670 918 E AmStub : Caused by: java.lang.NoClassDefFoundError: xx/oo/MySerializableObject
1094 07-09 22:25:29.927 670 918 E AmStub : ... 24 more
1095 07-09 22:25:29.927 670 918 E AmStub : Caused by: java.lang.ClassNotFoundException: Didn't find class "xx.oo.MySerializableObject" on path: DexPathList[[zip file "/system/framework/mediatek-op.jar"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
1096 07-09 22:25:29.927 670 918 E AmStub : at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:53)
1097 07-09 22:25:29.927 670 918 E AmStub : at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
1098 07-09 22:25:29.927 670 918 E AmStub : at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
1099 07-09 22:25:29.927 670 918 E AmStub : ... 24 more
1100 07-09 22:25:29.934 670 918 I ActivityManager: START u0 {flg=0x10000000 cmp=xx.oo/xx.oo.MyActivity (has extras) contextId=2722, taskId=2306 } from pid 23461


Android当中的坑

$
0
0

这里顺便记录下Android应用开发当中的一个一个的坑,很多时候我们都在面对这种问题,不同版本,不同厂商。。。
也许没有详尽/优雅的解决方法,但是至少问题在这里

1. SoundPool.play在Android 4.3当中没有办法looping播放

https://code.google.com/p/android/issues/detail?id=58113

2. Streaming播放声音的时候(比如AudioManager.MODE_IN_COMMUNICATION)无法切换外放
AudioManager.setMode(AudioManager.MODE_IN_CALL); // 切换成电话模式就可以切换
AudioManager.setSpeakerphoneOn(true);

3. 在某些机器上,比如插入耳机的时候无法切换外放

4.

OS X 上交叉编译在 Android 上运行的 libevent

$
0
0

下载官方源码 这里使用的是 libevent-2.0.21

首先看了下这几篇文章

http://blog.csdn.net/sozell/article/details/8898646
http://blog.csdn.net/cutesource/article/details/8970641
http://blog.chinaunix.net/uid-20514606-id-485808.html
注意,以下 $ANDROID_NDK 都是本机上 NDK 的路径

export ANDROID_ROOT=$ANDROID_NDK

export PATH=$PATH:$ANDROID_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin

 ./configure \
 --host=arm-linux-androideabi \
 CC=arm-linux-androideabi-gcc \
 LD=arm-linux-androideabi-ld \
 CPPFLAGS="-I$ANDROID_ROOT/platforms/android-14/arch-arm/usr/include/" \
 CFLAGS="-nostdlib" \
 LDFLAGS="-Wl,-rpath-link=$ANDROID_ROOT/platforms/android-14/arch-arm/usr/lib/ -L$ANDROID_ROOT/platforms/android-14/arch-arm/usr/lib/" \
 LIBS="-lc -lgcc -L$ANDROID_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9"

ln -s $ANDROID_ROOT/platforms/android-14/arch-arm/usr/lib/crtbegin_so.o
ln -s $ANDROID_ROOT/platforms/android-14/arch-arm/usr/lib/crtend_so.o

make

还有另外一种方法,看起来比较正规点

http://stackoverflow.com/questions/11929773/compiling-the-latest-openssl-for-android

以下是编译armv7-a的方法(其它arch需要稍微调整下)

注意,以下 $ANDROID_NDK 都是本机上 NDK 的路径

export NDK=$ANDROID_NDK
$NDK/build/tools/make-standalone-toolchain.sh --platform=android-14 --toolchain=arm-linux-androideabi-4.9 --install-dir=`pwd`/android-toolchain-arm
export TOOLCHAIN_PATH=`pwd`/android-toolchain-arm/bin
export TOOL=arm-linux-androideabi
export NDK_TOOLCHAIN_BASENAME=${TOOLCHAIN_PATH}/${TOOL}
export CC=$NDK_TOOLCHAIN_BASENAME-gcc
export CXX=$NDK_TOOLCHAIN_BASENAME-g++
export LINK=${CXX}
export LD=$NDK_TOOLCHAIN_BASENAME-ld
export AR=$NDK_TOOLCHAIN_BASENAME-ar
export RANLIB=$NDK_TOOLCHAIN_BASENAME-ranlib
export STRIP=$NDK_TOOLCHAIN_BASENAME-strip
export ARCH_FLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16"
export ARCH_LINK="-march=armv7-a -Wl,--fix-cortex-a8"
export CPPFLAGS=" ${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 "
export CXXFLAGS=" ${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions "
export CFLAGS=" ${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 "
export LDFLAGS=" ${ARCH_LINK} "

./configure --host=arm-linux-androideabi

就会在 .libs 下生成 so/a 档案

例子程序程序调用过程当中遇到的问题,具体完整代码参见 https://github.com/guohai/and-libevent

guohai@Hais-MacBook-Pro:~/Dev/work/idea/and-libevent/app/src/main/jni$ ndk-build V=1 -B
rm -f /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/arm64-v8a/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a-hard/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips64/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86_64/lib*.so
rm -f /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/arm64-v8a/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a-hard/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips64/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86_64/gdbserver
rm -f /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/arm64-v8a/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a-hard/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips64/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86_64/gdb.setup
[armeabi-v7a] Compile thumb  : demo_libevent <= demo_libevent.c
/Users/guohai/Dev/android-ndk-r10c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc -MMD -MP -MF /Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/objs/demo_libevent/demo_libevent.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector -no-canonical-prefixes -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=softfp -mthumb -Os -g -DNDEBUG -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I/Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni -DANDROID  -Wa,--noexecstack -Wformat -Werror=format-security    -I/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm/usr/include -c  /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/demo_libevent.c -o /Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/objs/demo_libevent/demo_libevent.o
[armeabi-v7a] Executable     : demo_libevent
/Users/guohai/Dev/android-ndk-r10c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ -Wl,--gc-sections -Wl,-z,nocopyreloc --sysroot=/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm -Wl,-rpath-link=/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm/usr/lib -Wl,-rpath-link=/Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a /Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/objs/demo_libevent/demo_libevent.o /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent.a /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent_core.a /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent_extra.a /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent_pthreads.a -lgcc -no-canonical-prefixes -march=armv7-a -Wl,--fix-cortex-a8  -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now  -L/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm/usr/lib -llog -lc -lm -o /Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/demo_libevent
/Users/guohai/Dev/android-ndk-r10c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent.a(event.o): in function evthread_make_base_notifiable:event.c(.text.evthread_make_base_notifiable+0x5c): error: undefined reference to 'eventfd'
collect2: ld returned 1 exit status
make: *** [/Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/demo_libevent] Error 1

eventfd 是 2.6.22 加入到内核当中的系统调用,然后默认写的 -L/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm/usr/lib 内核比较低,于是修改

APP_PLATFORM := android-14

编译通过

在模拟器上启动程序,配置端口转发,测试

guohai@Hais-MacBook-Pro:~$ adb forward tcp:9995 tcp:9995

guohai@Hais-MacBook-Pro:~$ telnet localhost 9995
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello, World!
Connection closed by foreign host.

服务器端的反馈

root@generic:/data/data # ./demo_libevent                                        
flushed answer
^CCaught an interrupt signal; exiting cleanly in two seconds.
done
root@generic:/data/data # exit

小结二零一四

$
0
0

看了下2014年的目标 小结二零一三,很多都没有完成。。。所以2015年的目标就是把2014年的完成[我知道你们会不相信 @_@]。

2014
中秋回家看了一次家人,然后还算经常地给他们通电话。。。

在一家Vans店看到别人玩滑板的视屏觉得很酷,然后自己买了块板开始玩,不过时间有限,努力训练也没有别人多,所以技术自然也不是特别好,处于一个需要认真训练才能跨过的坎,反正慢慢玩呗,有空晚上去滑滑,看别人滑滑,跟着大部队刷刷街

上半年还比较勤的去玩篮球,下半年就只能呵呵了

有一个事情还是算好的,现在大部分时间可以坐直了工作(以前都是弯着腰),形成了习惯,不过不知道对脊柱有没有什么不良影响

其它大部分时间应该都是工作,吃饭,睡觉,一直处于忙碌状态

android.util.Pair 引起的崩溃

$
0
0

博客好久没有更新过了。
一直都觉得自己没啥时间 囧囧

创业开始一直都在负责 App 相关的工作。
早上例行看了下昨日统计,崩溃率暴涨,但是就维持在 4 个用户,一看 Android 版本,都是 4.0.4,
心想肯定尼玛有碰到了不该用的 API。


FATAL EXCEPTION: h-262 262
PID: 2610
java.lang.NullPointerException
at android.util.Pair.hashCode(Pair.java:63)
at java.lang.Object.toString(Object.java:332)
at java.lang.StringBuilder.append(StringBuilder.java:202)
at java.util.AbstractMap.toString(AbstractMap.java:448)
at java.lang.StringBuilder.append(StringBuilder.java:202)
......
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at cc.beckon.service.a.h.run(l:159)

看了下最新的 android.util.Pair 代码,似乎没有什么问题,然后追溯这个文件的修改历史
Screen Shot 2015-10-06 at 12.34.01 PM
对于为 Null 的值在低版本的 Pair 上确实无法处理,回过头来看,在这条案例上没有测试到就直接上了,该打。

独立编译 Skia for Android

$
0
0

最近想了解下 Skia 相关的东西,想利用其中的一些 API 来做做优化,所以打算独立编译一个版本试试看。

https://skia.org/user/quick/android

使用的代码版本


commit 81bdbf8bed8b739c2b65ac576e89d0258276e6dc
Author: caryclark
Date: Wed Oct 21 04:16:19 2015 -0700

编译环境

Ubuntu 14.04.2

直接按照官方说明就可以编译出来,我这里是不想去下载一遍 NDK,所以进行了点改动。


http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin

如果机器上已经安装过对应版本的 NDK,可以修改以下文件直接生成 TOOLCHAIN(这个步骤不是必须的)

/mnt/extra/skia/platform_tools/android/bin/utils/setup_toolchain.sh


function default_toolchain() {
- TOOLCHAINS=${SCRIPT_DIR}/../toolchains
+ TOOLCHAINS=/home/ubuntu/dev

ANDROID_ARCH=${ANDROID_ARCH-arm}
LLVM=3.6
@@ -50,19 +50,13 @@ function default_toolchain() {
exportVar ANDROID_TOOLCHAIN "${TOOLCHAINS}/${TOOLCHAIN}/bin"

if [ ! -d "$ANDROID_TOOLCHAIN" ]; then
- mkdir -p $TOOLCHAINS
pushd $TOOLCHAINS
- curl -o $NDK.bin https://dl.google.com/android/ndk/android-ndk-$NDK-$HOST-x86_64.bin
- chmod +x $NDK.bin
- ./$NDK.bin -y
./android-ndk-$NDK/build/tools/make-standalone-toolchain.sh \
--arch=$ANDROID_ARCH \
--llvm-version=$LLVM \
--platform=android-$API \
--install_dir=$TOOLCHAIN
cp android-ndk-$NDK/prebuilt/android-$ANDROID_ARCH/gdbserver/gdbserver $TOOLCHAIN
- rm $NDK.bin
- rm -rf android-ndk-$NDK
popd
fi

生成过一次 TOOLCHAIN 之后也可以把

export ANDROID_TOOLCHAIN=/home/ubuntu/dev/arm-r10e-14/bin
export PATH=$ANDROID_TOOLCHAIN:$PATH

手动加在到配置文件里面去(这个步骤不是必须的)


./platform_tools/android/bin/android_ninja -d nexus_5

然后就是等待编译,如果中途编译 APK 的时候却少一些特定版本的 Build Tool 的时候修改下 App 当中使用版本就好了,或者也可以去更新代码当中对应的版本
App 代码位于

/mnt/extra/skia/platform_tools/android/apps/

编译完成之后就可以在
/mnt/extra/skia/out/config/android-nexus_5/Debug
下看到 so 了

Viewing all 45 articles
Browse latest View live