Mode Decision(模式选择)决定一个宏块以何种类型进行分割。宏块的分割类型有以下几种:

  1. //P_Skip and B_Skip means that nothing need to be encoded for this macroblock ,
  2. // just use the mv predicted to restruct the macroblock
  3. //B_Direct means use no mvd and no refidx,
  4. // just use the mv abtain from Direct Algorithm and the residue mb
  5. // base on such mv to restruct the macroblock.
  6. // On Direct mode, we need to encode redisual
  7. enum {
  8. PSKIP = 0, //encode nothing
  9. BSKIP_DIRECT = 0, //skip means encode nothing, direct means encode residual
  10. P16x16 = 1, //16x16 on p or b slice
  11. P16x8 = 2, //16x8 on p or b slice
  12. P8x16 = 3, //8x16 on p or b slice
  13. SMB8x8 = 4, //sub macroblock 8x8 on p or b slice
  14. SMB8x4 = 5, //sub macroblock 8x4 on p or b slice
  15. SMB4x8 = 6, //sub macroblock 4x8 on p or b slice
  16. SMB4x4 = 7, //sub macroblock 4x4 on p or b slice
  17. P8x8 = 8, //set of sub macroblock modes
  18. I4MB = 9, //4x4 on i slice
  19. I16MB = 10, //16x16 on i slice
  20. IBLOCK = 11, //the same with I4MB
  21. SI4MB = 12, //
  22. I8MB = 13, //8x8 on i slice
  23. IPCM = 14, //PCM mode
  24. MAXMODE = 15
  25. } MBModeTypes;

模式选择就是通过某种算法得到最优的宏块分割类型。不同算法在流程、最优分割方式选择上会有区别,但是都遵循h.264的标准。

宏块与子宏块

  1. macroblock_layer( ) {
  2. mb_type
  3. if( mb_type = = I_PCM ) {
  4. while( !byte_aligned( ) )
  5. pcm_alignment_zero_bit
  6. for( i = 0; i < 256; i++ )
  7. pcm_sample_luma[ i ]
  8. for( i = 0; i < 2 * MbWidthC * MbHeightC; i++ )
  9. pcm_sample_chroma[ i ]
  10. } else {
  11. noSubMbPartSizeLessThan8x8Flag = 1
  12. if( mb_type != I_NxN &&
  13. MbPartPredMode( mb_type, 0 ) != Intra_16x16 &&
  14. NumMbPart( mb_type ) = = 4 ) {
  15.  
  16. sub_mb_pred( mb_type ) //子宏块预测
  17. for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
  18. if( sub_mb_type[ mbPartIdx ] != B_Direct_8x8 ) {
  19. if( NumSubMbPart( sub_mb_type[ mbPartIdx ] ) > 1 )
  20. noSubMbPartSizeLessThan8x8Flag = 0
  21. } else if( !direct_8x8_inference_flag )
  22. noSubMbPartSizeLessThan8x8Flag = 0
  23. } else {
  24. if( transform_8x8_mode_flag && mb_type = = I_NxN )
  25. transform_size_8x8_flag
  26. mb_pred( mb_type ) //宏块预测
  27. }
  28. if( MbPartPredMode( mb_type, 0 ) != Intra_16x16 ) {
  29. coded_block_pattern
  30. if( CodedBlockPatternLuma > 0 &&
  31. transform_8x8_mode_flag && mb_type != I_NxN &&
  32. noSubMbPartSizeLessThan8x8Flag &&
  33. ( mb_type != B_Direct_16x16 | | direct_8x8_inference_flag ) )
  34.  
  35. transform_size_8x8_flag
  36. }
  37. if( CodedBlockPatternLuma > 0 | | CodedBlockPatternChroma > 0 | | MbPartPredMode( mb_type, 0 ) = = Intra_16x16 ) {
  38.  
  39. mb_qp_delta
  40. residual( )
  41. }
  42. }
  43. }

上面是宏块层的语法,可以看到宏块预测可以分为两大类:宏块预测、子宏块预测,这两类预测是相互独立的。有兴趣可以去查看宏块结构(h.264语法结构分析的slice_data之后的部分)、宏块与子宏块类型(h.264宏块与子宏块类型

子宏块类型则可以统一为一种类型P8x8,每个宏块有4个P8x8的子宏块,4个子宏块独立进行子宏块预测,每个子宏块都可以为不同的子宏块类型。

Chroma模式选择

Chroma宏块只分为intra与inter两种类型,并不再细分。标准规定了Chroma宏块的预测方式是受到luma的预测方式的制约的。当luma是以intra进行预测时,chroma宏块才会进行intra预测;当luma是以inter进行预测时,chroma宏块进行的是inter预测(Chroma inter预测不会自行预测,而是通过luma预测结果进行缩放处理后得到的Chroma mv)。

宏块预测中,只有I4MB, I16MB, I8MB时Chroma宏块才会采用intra预测:

  1. //只有当luma的预测模式为intra时,才会进行Chroma的intra预测
  2. mb_pred( mb_type ) {
  3. if( MbPartPredMode( mb_type, 0 ) = = Intra_4x4 | |
  4. MbPartPredMode( mb_type, 0 ) = = Intra_8x8 | |
  5. MbPartPredMode( mb_type, 0 ) = = Intra_16x16 ) {
  6.  
  7. if( MbPartPredMode( mb_type, 0 ) = = Intra_4x4 )
  8. for( luma4x4BlkIdx=0; luma4x4BlkIdx<16; luma4x4BlkIdx++ ) {
  9. prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ]
  10. if( !prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ] )
  11. rem_intra4x4_pred_mode[ luma4x4BlkIdx ]
  12. }
  13. if( MbPartPredMode( mb_type, 0 ) = = Intra_8x8 )
  14. for( luma8x8BlkIdx=0; luma8x8BlkIdx<4; luma8x8BlkIdx++ ) {
  15. prev_intra8x8_pred_mode_flag[ luma8x8BlkIdx ]
  16. if( !prev_intra8x8_pred_mode_flag[ luma8x8BlkIdx ] )
  17. rem_intra8x8_pred_mode[ luma8x8BlkIdx ]
  18. }
  19. if( chroma_format_idc != 0 )
  20. intra_chroma_pred_mode
  21. } else if( MbPartPredMode( mb_type, 0 ) != Direct ) {
  22. for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)
  23. if( ( num_ref_idx_l0_active_minus1 > 0 | |
  24. mb_field_decoding_flag ) &&
  25. MbPartPredMode( mb_type, mbPartIdx ) != Pred_L1 )
  26.  
  27. ref_idx_l0[ mbPartIdx ]
  28. for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)
  29. if( ( num_ref_idx_l1_active_minus1 > 0 | |
  30. mb_field_decoding_flag ) &&
  31. MbPartPredMode( mb_type, mbPartIdx ) != Pred_L0 )
  32.  
  33. ref_idx_l1[ mbPartIdx ]
  34. for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)
  35. if( MbPartPredMode ( mb_type, mbPartIdx ) != Pred_L1 )
  36. for( compIdx = 0; compIdx < 2; compIdx++ )
  37. mvd_l0[ mbPartIdx ][ 0 ][ compIdx ]
  38. for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)
  39. if( MbPartPredMode( mb_type, mbPartIdx ) != Pred_L0 )
  40. for( compIdx = 0; compIdx < 2; compIdx++ )
  41. mvd_l1[ mbPartIdx ][ 0 ][ compIdx ]
  42. }
  43. }

子宏块预测中没有Chroma intra预测:

  1. //可以看到子宏块预测时,没有Chroma的intra预测
  2. sub_mb_pred( mb_type ) {
  3. for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
  4. sub_mb_type[ mbPartIdx ]
  5. for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
  6. if( ( num_ref_idx_l0_active_minus1 > 0 | | mb_field_decoding_flag ) &&
  7. mb_type != P_8x8ref0 &&
  8. sub_mb_type[ mbPartIdx ] != B_Direct_8x8 &&
  9. SubMbPredMode( sub_mb_type[ mbPartIdx ] ) != Pred_L1 )
  10.  
  11. ref_idx_l0[ mbPartIdx ]
  12. for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
  13. if( (num_ref_idx_l1_active_minus1 > 0 | | mb_field_decoding_flag ) &&
  14. sub_mb_type[ mbPartIdx ] != B_Direct_8x8 &&
  15. SubMbPredMode( sub_mb_type[ mbPartIdx ] ) != Pred_L0 )
  16.  
  17. ref_idx_l1[ mbPartIdx ]
  18. for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
  19. if( sub_mb_type[ mbPartIdx ] != B_Direct_8x8 &&
  20. SubMbPredMode( sub_mb_type[ mbPartIdx ] ) != Pred_L1 )
  21.  
  22. for( subMbPartIdx = 0;
  23. subMbPartIdx < NumSubMbPart( sub_mb_type[ mbPartIdx ] );
  24. subMbPartIdx++)
  25.  
  26. for( compIdx = 0; compIdx < 2; compIdx++ )
  27. mvd_l0[ mbPartIdx ][ subMbPartIdx ][ compIdx ]
  28. for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )
  29. if( sub_mb_type[ mbPartIdx ] != B_Direct_8x8 &&
  30. SubMbPredMode( sub_mb_type[ mbPartIdx ] ) != Pred_L0 )
  31.  
  32. for( subMbPartIdx = 0;
  33. subMbPartIdx < NumSubMbPart( sub_mb_type[ mbPartIdx ] );
  34. subMbPartIdx++)
  35.  
  36. for( compIdx = 0; compIdx < 2; compIdx++ )
  37. mvd_l1[ mbPartIdx ][ subMbPartIdx ][ compIdx ]
  38. }

Mode Decision

JM18.6中有几种模式选择的算法,下面来分析一下low与high这两种算法的流程。

Mode Decision Low

该过程非常主要的一个特点是Chroma不参与模式选择

简述一下Low的流程:

  1. inter的宏块类型(P16x16, P16x8, P8x16)选择。
  2. inter的子宏块类型(SMB8x8, SMB8x4, SMB4x8, SMB4x4)选择,每个8x8都可以独立选择不同的分割方式;如果8x8变换方式可用的话,则会多进行一次只采用SMB8x8并采用8x8变换的编码方式,由此看出8x8变换在子宏块类型中只用于SMB8x8。
  3. Skip, FindSkipModeMotionVector此处无作用。
  4. Direct
  5. I8MB,在4个8x8子宏块中可以分别选择不同的预测模式,该预测模式与I4MB一样有9种;在mode_decision_for_I8x8_blocks最后会进行残差编码,宏块重建。
  6. I4MB,在16个4x4块中可以分别选择不同的预测模式,预测模式共9种;在mode_decision_for_I4x4_blocks最后会进行残差编码,宏块重建。
  7. I16MB,在residual_transform_quant_luma_16x16最后会进行残差计算,宏块重建。
  8. 上面的步骤已经通过rdcost选择到了最佳的宏块分割模式,这里会进行后续的参数设置,其中最主要的就是非intra模式的残差编码与宏块重建luma_residual_coding。
  9. Chroma,可以注意到,在Low的流程中Chroma一直没有参与到模式选择当中。最后进行Chroma的intra预测,并根据前面luma所得的当前宏块为intra还是inter模式,选择相应的模式进行编码。

Mode Decision High

该过程中chroma宏块也参与模式选择。

简述一下high的流程:

  1. SKIP, 如果是bslice调用Get_Direct_Motion_Vectors,pslice则调用FindSkipModeMotionVector获得运动向量。
  2. inter的宏块类型(P16x16, P16x8, P8x16)选择。
  3. inter的子宏块类型(SMB8x8, SMB8x4, SMB4x8, SMB4x4)选择,每个8x8都可以独立选择不同的分割方式;如果8x8变换方式可用的话,则会多进行一次只采用SMB8x8并采用8x8变换的编码方式,由此看出8x8变换在子宏块类型中只用于SMB8x8。
  4. chroma预测模式,如果指定了FastCrIntraDecision,则挑选出最佳的chroma模式,否则得到的是chroma模式的范围(DC_PRED_8 ~ PLANE_8)。
  5. 根据所得到的chroma模式范围进行循环。
  6. 在所有luma 模式中选择最佳的模式。
  7. compute_mode_RD_cost中首先筛选chroma模式,只有三种情况才可以往下选择最佳luma模式:

    • FastCrIntraDecision,表明只有一次chroma循环,并且循环前已经选出了最佳的chroma模式;
    • DC_PRED_8,chroma DC模式可以搭配所有的luma模式;
    • intra,luma intra模式可以搭配所有的chroma intra模式。
  8. Bslice & P16x16的情况,再次(?)检查forward,backward,both,bi-pred中,哪种方式最佳。
  9. 如果输入参数指定了transform 8x8,那么对transform8x8与transform4x4分别计算残差。
  10. < P8x8,也就是P16x16, P16x8, P8x16的残差编码,宏块重建。
  11. P8x8,也就是SMB8x8, SMB8x4, SMB4x8, SMB4x4宏块重建,他们的残差计算在子宏块预测时已经计算编码过,并且得到了子宏块的重建块,所以这里只是单纯把子宏块的重建块合并起来。
  12. I4MB,在16个4x4块中可以分别选择不同的预测模式,预测模式共9种;在mode_decision_for_I4x4_blocks最后会进行残差编码,宏块重建。
  13. I16MB,在residual_transform_quant_luma_16x16最后会进行残差编码,宏块重建。
  14. I8MB,在4个8x8子宏块中可以分别选择不同的预测模式,该预测模式与I4MB一样有9种;在mode_decision_for_I8x8_blocks最后会进行残差编码,宏块重建。
  15. IPCM,重建块就是编码块。
  16. Chroma残差编码,其实函数内部分别包含了intra与inter的预测。只有luma在intra模式下,才能进行chroma的intra预测。最后进行chroma的残差编码,宏块重建。
  17. 在每个luma模式最后,都计算出rdcost,然后与前面得到的最低rdcost比较,选择最佳的分割模式。

LOW与HIGH的共同点

可以看到他们在inter模式选择时流程大致一样的。先得到宏块的最佳分割模式,然后得到4个子宏块的最佳分割模式。下面大致浏览一下PartitionMotionSearch与SubPartitionMotionSearch的流程。

LOW与HIGH的不同点

不同点大致分为流程上,最优分割模式选择(计算rdcost)的差异。

  • Low在对每种分割模式预测完后,立刻进行rdcost计算,用得到的rdcost对比前面已经得到的最佳cost,从而得到最佳模式。在得到最佳模式后,再进行残差编码与重建。
  • High统一把对比cost并得到最佳模式这个过程写到compute_mode_RD_cost里面。在前面进行完成运动预测后,进入该函数对9种分割模式进行残差编码,宏块重建,cost计算与对比。其中4种intra分割模式是在这个函数内部才分别进行预测的。
  • Low的rdcost计算并不像high的那么严谨,只是简单地算出distortion与残差系数以外的bit数。Low的rdcost不包括chroma所占用的bit。
  • High的rdcost会计算经由熵编码后得到的bit,并且包含了chroma所占用的bit,因此更加精准。但是也会相应地增加编码时间。

宏块重建

宏块重建是指把宏块反量化、反变换后得到的残差,加上参考帧中对应运动向量位置的宏块后重新构建当前宏块的过程。该过程一般处于反量化、反变换步骤之后,而反量化、反变换处于变换、量化这两个过程之后,即残差编码过程之内。因此,残差编码与宏块重建基本上都是一起进行的。

  1. /*!
  2. ************************************************************************
  3. * \brief
  4. * The routine performs transform,quantization,inverse transform,
  5. * adds the diff to the prediction and writes the result to the
  6. * decoded luma frame.
  7. *
  8. * \par Input:
  9. * currMB: Current macroblock.
  10. * pl: Color plane for 4:4:4 coding.
  11. * block_x,block_y: Block position inside a macro block (0,4,8,12).
  12. * intra: Intra block indicator.
  13. *
  14. * \par Output_
  15. * nonzero: 0 if no levels are nonzero. \n
  16. * 1 if there are nonzero levels.\n
  17. * coeff_cost: Coeff coding cost for thresholding consideration.\n
  18. ************************************************************************
  19. */
  20. int residual_transform_quant_luma_4x4(Macroblock *currMB, ColorPlane pl, int block_x,int block_y, int *coeff_cost, int intra)
  21. {
  22. int nonzero = FALSE;
  23.  
  24. int pos_x = block_x >> BLOCK_SHIFT;
  25. int pos_y = block_y >> BLOCK_SHIFT;
  26. int b8 = 2*(pos_y >> 1) + (pos_x >> 1) + (pl<<2);
  27. int b4 = 2*(pos_y & 0x01) + (pos_x & 0x01);
  28. Slice *currSlice = currMB->p_Slice;
  29. VideoParameters *p_Vid = currSlice->p_Vid;
  30.  
  31. imgpel **img_enc = p_Vid->enc_picture->p_curr_img;
  32. imgpel **mb_pred = currSlice->mb_pred[pl];
  33. int **mb_ores = currSlice->mb_ores[pl];
  34.  
  35. if (check_zero(&mb_ores[block_y], block_x) != 0) // check if any coefficients in block
  36. {
  37. int **mb_rres = currSlice->mb_rres[pl];
  38. int max_imgpel_value = p_Vid->max_imgpel_value;
  39. int qp = (p_Vid->yuv_format==YUV444 && !currSlice->P444_joined)? currMB->qp_scaled[(int)(p_Vid->colour_plane_id)]: currMB->qp_scaled[pl];
  40. QuantParameters *p_Quant = p_Vid->p_Quant;
  41. QuantMethods quant_methods;
  42. quant_methods.ACLevel = currSlice->cofAC[b8][b4][0];
  43. quant_methods.ACRun = currSlice->cofAC[b8][b4][1];
  44.  
  45. //block_x,block_y here is the position of a block on a Macroblock with the unit of pixel
  46. quant_methods.block_x = block_x;
  47. quant_methods.block_y = block_y;
  48. quant_methods.qp = qp;
  49. quant_methods.q_params = p_Quant->q_params_4x4[pl][intra][qp];
  50. quant_methods.fadjust = p_Vid->AdaptiveRounding ? (&p_Vid->ARCofAdj4x4[pl][currMB->ar_mode][block_y]) : NULL;
  51. quant_methods.coeff_cost = coeff_cost;
  52. quant_methods.pos_scan = currMB->is_field_mode ? FIELD_SCAN : SNGL_SCAN;
  53. quant_methods.c_cost = COEFF_COST4x4[currSlice->disthres];
  54.  
  55. currMB->subblock_x = ((b8&0x1)==0) ? (((b4&0x1)==0)? 0: 4) : (((b4&0x1)==0)? 8: 12); // horiz. position for coeff_count context
  56. currMB->subblock_y = (b8<2) ? ((b4<2) ? 0: 4) : ((b4<2) ? 8: 12); // vert. position for coeff_count context
  57.  
  58. // Forward 4x4 transform
  59. forward4x4(mb_ores, currSlice->tblk16x16, block_y, block_x);
  60.  
  61. // Quantization process
  62. nonzero = currSlice->quant_4x4(currMB, &currSlice->tblk16x16[block_y], &quant_methods);
  63.  
  64. // Decoded block moved to frame memory
  65. if (nonzero)
  66. {
  67. // Inverse 4x4 transform
  68. inverse4x4(currSlice->tblk16x16, mb_rres, block_y, block_x);
  69.  
  70. // generate final block
  71. sample_reconstruct (&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], &mb_rres[block_y], block_x, currMB->pix_x + block_x, BLOCK_SIZE, BLOCK_SIZE, max_imgpel_value, DQ_BITS);
  72. }
  73. else // if (nonzero) => No transformed residual. Just use prediction.
  74. {
  75. copy_image_data_4x4(&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], currMB->pix_x + block_x, block_x);
  76. }
  77. }
  78. else
  79. {
  80. currSlice->cofAC[b8][b4][0][0] = 0;
  81. copy_image_data_4x4(&img_enc[currMB->pix_y + block_y], &mb_pred[block_y], currMB->pix_x + block_x, block_x);
  82. }
  83.  
  84. return nonzero;
  85. }

h.264 Mode Decision的更多相关文章

  1. 【HEVC帧间预测论文】P1.2 An Efficient Inter Mode Decision Approach for H.264 Video Codin

    参考:An Efficient Inter Mode Decision Approach for H.264 Video Coding <HEVC标准介绍.HEVC帧间预测论文笔记>系列博 ...

  2. (转载)H.264码流的RTP封包说明

    H.264的NALU,RTP封包说明(转自牛人) 2010-06-30 16:28 H.264 RTP payload 格式 H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) ...

  3. H.264的优势和主要特点

    H.264,同时也是MPEG-4第十部分,是由ITU-T视频编码专家组(VCEG)和ISO/IEC动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压 ...

  4. Android IOS WebRTC 音视频开发总结(七九)-- WebRTC选择H.264的四大理由

    本文主要介绍WebRTC选择H.264的理由(我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacke ...

  5. 使用VideoToolbox硬编码H.264<转>

    文/落影loyinglin(简书作者)原文链接:http://www.jianshu.com/p/37784e363b8a著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. ======= ...

  6. ASP.NET MVC程序播放H.264视频

    在这篇之前,Insus.NET不管是在ASP.NET还是ASP.NET MVC实现很多视频播放,你可以参考这篇链接:http://www.cnblogs.com/insus/category/4650 ...

  7. 获得H.264视频分辨率的方法

    转自:http://www.cnblogs.com/likwo/p/3531241.html 在使用ffmpeg解码播放TS流的时候(例如之前写过的UDP组播流),在连接时往往需要耗费大量时间.经过d ...

  8. x264 - 高品质 H.264 编码器

    转自:http://www.5i01.cn/topicdetail.php?f=510&t=3735840&r=18&last=48592660 H.264 / MPEG-4 ...

  9. FMS发布视频流H.264如何设置

    FMS这个话题由来已久,H.264这个编码格式也由来已久.FMS不叫FMS了,改叫AMS了.因为是Adobe. 今天就说说flash发布流媒体视频,以H.264编码出现的问题.在网上找,大把的关于as ...

随机推荐

  1. Nginx+keepalived做双机热备加tomcat负载均衡

    Nginx+keepalived做双机热备加tomcat负载均衡 环境说明: nginx1:192.168.2.47 nginx2:192.168.2.48 tomcat1:192.168.2.49 ...

  2. 在cmd窗口下运行Java程序时无法找到主类的解决办法

    我是Java的初学者,昨天在cmd窗口下运行一段Java程序时总是有问题,可以编译但无法执行. 也就是javac时正确,一旦java时就不对了,提示找不到或无法加载主类,经百度谷歌再加上自己的摸索终于 ...

  3. php include 与 require 起底[转]

    转自 http://www.guangla.com/post/2014-01-24/40060857811 起因: 一朋友面试被问到,php的include和require的区别,这个可能是面试中出现 ...

  4. Bellman_ford POJ 3259 Wormholes

    Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 41728   Accepted: 15325 Descr ...

  5. 码表 ASCII Unicode GBK UTF-8

    2017-1-3 [ASCII]一个字节(7位,128个字符,2个16进制) 不包含中文 ASCII(American Standard Code for Information Interchang ...

  6. javascript 实用函数

    1.去除字符串空格 /*去左空格*/ function ltrim(s) { return s.replace(/^(\s*| *)/, ""); } /*去右空格*/ funct ...

  7. C#实现发送邮件

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. UISegmentControl 、UIStepper

    UISegmentControl .UIStepper UISegmentControl 1. UISegmentedControl *segmentControl = [[UISegmentedCo ...

  9. QT实现单个EXE文件

    有时候发布用Qt写的软件是件令人烦恼的事情,明明发布的只是一个简单功能的小软件,非得再附上一堆超大的动态链接库,实在让人觉得汗颜 . 在可执行文件单文件化方面,有多种方法.常用的是编译并使用静态 Qt ...

  10. Multiple dex files define Lcom/sina/sso/RemoteSSO错误解决办法

    在安卓上遇到了Multiple dex files define Lcom/sina/sso/RemoteSSO的编译错误 在网上找解决办法 搜到了解决办法是这样的 方案1:Eclipse->P ...