X264編碼庫libx264實現真正的視頻編解碼,該編解碼算法是基於塊的混合編碼技術,即幀內/幀間預測,然后對預測值變換、量化,最后熵編碼所得。
編碼幀的類型分為I幀(x264_type_i)、P幀(x264_type_p)、B幀(x264_type_b),在H264中叫做圖像片Slice。
X264把整幀圖像看作一個Slice,片中有slice_type_i、slice_type_p、slice_type_b之分。
I幀只有slice_type_i,P幀有slice_type_i、slice_type_p,B幀三種片都有。
X264的H264視頻編碼過程可以分為三個步驟:首先根據規則判定當前幀的編碼類型,如果是B幀,要緩沖存放、獲取;然后對待編碼圖像進行幀內預測、幀間預測、整數DCT變換、量化和熵編碼;最后把壓縮的H264數據進行NAL層打包輸出。
X264編碼器有關的重要結構體:
x264_image_t:實際參與編碼的編碼幀圖像信息。
typedef struct { int i_csp; //圖像空間顏色 int i_plane; //圖像平面數目 int i_stride[4]; //每個圖像平面的跨度,也就是每一行數據的字節數 uint8_t *plane[4]; //每個圖像平面存放數據的起始地址,plane[0]是Y平面,plane[1]是U平面,plane[2]是V平面 }x264_image_t; //待編碼的圖像
x264_picture_t:x264編碼器定義便於控制的圖像幀,描述一幀的特征。包含x264_image_t和x264_param_t結構體。
typedef struct { int i_type; //幀的類型,初始化為auto,在編碼過程自行控制 int i_qpplus1; //此參數減1代表當前幀的量化參數值 int i_pic_struct; //幀的結構類型 int b_keyframe; //輸出是否是關鍵幀 int64_t i_pts; //一幀的顯示時間戳 int64_t i_dts; //輸出解碼時間戳 x264_param_t *param; x264_image_t img; x264_image_properties_t prop; x264_hrd_t hrd_timing; void *opaque; } x264_picture_t; //x264編碼視頻幀
x264_param_t:初始化編碼器。
typedef struct { unsigned int cpu; //CPU 標志位 int i_threads; //並行編碼多幀 int b_sliced_threads; //如果設置為false,一個slice只編碼成一個NALU,默認值是true int b_deterministic; //是否允許非確定性時線程優化 int b_cpu_independent; //強制采用典型行為,而不是采用獨立於CPU的優化算法 int i_sync_lookahead; //線程超前緩存幀數 int i_width; //視頻圖像的寬 int i_height; //視頻圖像的高 int i_csp; //色彩空間設置,僅支持I420 int i_level_idc; //編碼復雜度 int i_frame_total; //編碼幀的總數, 不知道默認為0即可 struct { int i_sar_height; //樣本寬高比的高度 int i_sar_width; //樣本寬高比的寬度 int i_vidformat; //視頻在編碼/數字化之前是什么類型,默認"undef(不設置)" int b_fullrange; //樣本亮度和色度的計算方式,默認"off" int i_colorprim; //原始色度格式,默認"undef" int i_transfer; //轉換方式,默認"undef" int i_colmatrix; //設置從RGB計算得到亮度和色度所用的矩陣系數,默認"undef" int i_chroma_loc; //設置色度采樣位置,范圍0~5,默認0 } vui; //vui參數集 : 視頻可用性信息、視頻標准化選項 //比特流參數 int i_frame_reference; //最大參考幀數目 int i_dpb_size; //Decoded picture buffer size int i_keyint_max; //設定IDR幀之間的最間隔,在此間隔設置IDR關鍵幀 int i_keyint_min; //設定IDR幀之間的最小間隔, 場景切換小於此值編碼位I幀, 而不是 IDR幀 int i_scenecut_threshold; //場景切換閾值,插入I幀 int b_intra_refresh; //是否使用周期幀內刷新替代IDR幀 int i_bframe; //兩個參考幀之間的B幀數目 int i_bframe_adaptive; //自適應B幀判定, 可選取值:X264_B_ADAPT_FAST等 int i_bframe_bias; //控制B幀替代P幀的概率,范圍-100 ~ +100,該值越高越容易插入B幀,默認0 int i_bframe_pyramid; //允許部分B幀為參考幀,可選取值:0=off, 1=strict hierarchical, 2=normal int b_open_gop; //幀間的預測都是在GOP中進行,后一個GOP會參考前一個GOP的信息 int b_bluray_compat; //支持藍光碟 int b_deblocking_filter; //去塊濾波開關 int i_deblocking_filter_alphac0;//[-6, 6] -6 light filter, 6 strong int i_deblocking_filter_beta; //[-6, 6] 同上 int b_cabac; //自適應算術編碼cabac開關 int i_cabac_init_idc; //給出算術編碼初始化時表格的選擇 int b_interlaced; //隔行掃描 int b_constrained_intra; int i_cqm_preset; //自定義量化矩陣(CQM), 初始化量化模式為flat char *psz_cqm_file; //讀取JM格式的外部量化矩陣文件,忽略其他cqm選項 uint8_t cqm_4iy[16]; //used only if i_cqm_preset == X264_CQM_CUSTOM uint8_t cqm_4py[16]; uint8_t cqm_4ic[16]; uint8_t cqm_4pc[16]; uint8_t cqm_8iy[64]; uint8_t cqm_8py[64]; uint8_t cqm_8ic[64]; uint8_t cqm_8pc[64]; void(*pf_log)(void *, int i_level, const char *psz, va_list); //日志函數 void *p_log_private; int i_log_level; //日志級別,不需要打印編碼信息時直接注釋掉即可 int b_visualize; //是否顯示日志 char *psz_dump_yuv; //重建幀的文件名 struct { unsigned int intra; //幀內分區 unsigned int inter; //幀間分區 int b_transform_8x8; int i_weighted_pred; //P幀權重 int b_weighted_bipred; //B幀隱式加權 int i_direct_mv_pred; //時間空間運動向量預測模式 int i_chroma_qp_offset; //色度量化步長偏移量 int i_me_method; //運動估計算法 (X264_ME_*) int i_me_range; //整像素運動估計搜索范圍 (from predicted mv) int i_mv_range; //運動矢量最大長度. -1 = auto, based on level int i_mv_range_thread; //線程之間的最小運動向量緩沖. -1 = auto, based on number of threads. int i_subpel_refine; //亞像素運動估計質量 int b_chroma_me; //亞像素色度運動估計和P幀的模式選擇 int b_mixed_references; //允許每個宏塊的分區有它自己的參考號 int i_trellis; //Trellis量化提高效率,對每個8x8的塊尋找合適的量化值 int b_fast_pskip; //快速P幀跳過檢測 int b_dct_decimate; //P幀變換系數閾值 int i_noise_reduction; //自適應偽盲區 int b_psy; //Psy優化開關,可能會增強細節 float f_psy_rd; //Psy RD強度 float f_psy_trellis; //Psy Trellis強度 int i_luma_deadzone[2]; //亮度量化中使用的盲區大小,{ 幀間, 幀內 } int b_psnr; //計算和打印PSNR信息 int b_ssim; //計算和打印SSIM信息 } analyse; //編碼分析參數 struct { int i_rc_method; //碼率控制方式:X264_RC_CQP恆定質量,X264_RC_CRF恆定碼率, X264_RC_ABR平均碼率 int i_qp_constant; //指定P幀的量化值,0 - 51,0表示無損 int i_qp_min; //允許的最小量化值,默認10 int i_qp_max; //允許的最大量化值,默認51 int i_qp_step; //量化步長,即相鄰兩幀之間量化值之差的最大值 int i_bitrate; //平均碼率大小 float f_rf_constant; //1pass VBR, nominal QP. 實際質量,值越大圖像越花,越小越清晰 float f_rf_constant_max; //最大碼率因子 float f_rate_tolerance; //允許的誤差 int i_vbv_max_bitrate; //平均碼率模式下,最大瞬時碼率,默認0 int i_vbv_buffer_size; //碼率控制緩沖區的大小,單位kbit,默認0 float f_vbv_buffer_init; //設置碼率控制緩沖區(VBV)緩沖達到多滿(百分比),才開始回放,范圍0~1.0,默認0.9 float f_ip_factor; //I幀和P幀之間的量化因子(QP)比值,默認1.4 float f_pb_factor; //P幀和B幀之間的量化因子(QP)比值,默認1.3 int i_aq_mode; //自適應量化(AQ)模式。0:關閉AQ;1:允許AQ在整個視頻中和幀內重新分配碼;2:自方差AQ(實驗階段),嘗試逐幀調整強度。 float f_aq_strength; //AQ強度,減少平趟和紋理區域的塊效應和模糊度 int b_mb_tree; //是否開啟基於macroblock的qp控制方法 int i_lookahead; //決定mbtree向前預測的幀數 int b_stat_write; //是否將統計數據寫入到文件psz_stat_out中 char *psz_stat_out; //輸出文件用於保存第一次編碼統計數據 int b_stat_read; //是否從文件psz_stat_in中讀入統計數據 char *psz_stat_in; //輸入文件存有第一次編碼的統計數據 float f_qcompress; //量化曲線(quantizer curve)壓縮因子。0.0 => 恆定比特率,1.0 => 恆定量化值 float f_qblur; //時間上模糊量化,減少QP的波動(after curve compression) float f_complexity_blur; //時間上模糊復雜性,減少QP的波動(before curve compression) x264_zone_t *zones; //碼率控制覆蓋 int i_zones; //number of zone_t's char *psz_zones; //指定區的另一種方法 } rc; //碼率控制參數 //Muxing復用參數 int b_aud; //生成訪問單元分隔符 int b_repeat_headers; //是否復制sps和pps放在每個關鍵幀的前面 int b_annexb; //值為true,則NALU之前是4字節前綴碼0x00000001;值為false,則NALU之前的4個字節為NALU長度 int i_sps_id; //sps和pps的id號 int b_vfr_input; //VFR輸入。1 :時間基和時間戳用於碼率控制 0 :僅幀率用於碼率控制 uint32_t i_fps_num; //幀率的分子 uint32_t i_fps_den; //幀率的分母 uint32_t i_timebase_num; //時間基的分子 uint32_t i_timebase_den; //時間基的分母 int b_pulldown; int b_pic_struct; //強制在Picture Timing SEI傳送pic_struct. 默認是未開啟 int b_fake_interlaced; int i_slice_max_size; //每個slice的最大字節數,包括預計的NAL開銷 int i_slice_max_mbs; //每個slice的最大宏塊數,重寫i_slice_count int i_slice_count; //每幀slice的數目,每個slice必須是矩形 } x264_param_t;
x264_nal_t:x264_nal_t里的數據在下一次調用x264_encoder_encode之后就無效了,因此要在調用或者使用之前使用它。
typedef struct { int i_ref_idc; // Nal的優先級 int i_type; // Nal的類型 int b_long_startcode; // 是否采用長前綴碼0x00000001 int i_first_mb; // 如果Nal為一條帶,則表示該條帶第一個宏塊的指數 int i_last_mb; // 如果Nal為一條帶,則表示該條帶最后一個宏塊的指數 int i_payload; // payload 的字節大小 uint8_t *p_payload; // 存放編碼后的數據,已經封裝成Nal單元 } x264_nal_t;
X264編碼器有關的功能函數:
功能函數包括VCL編碼和NAL打包。
VCL編碼函數包括:
創建編碼器x264_encoder_open();
編碼圖像x264_encoder_encode();
關閉編碼器x264_encoder_close();
NAL打包函數:
x264_nal_encode();
//x264_picture_alloc:申請一幀圖像空間,需要調用x264_picture_clean釋放申請的內存 void x264_picture_alloc(x264_picture_t *pic, int i_csp, int i_width, int i_height); //x264_picture_clean:釋放x264_picture_alloc申請的有關資源,視頻結構體是x264_picture_t void x264_picture_clean(x264_picture_t *pic); //x264_encoder_open:創建編碼器句柄,讀入x264_param_t的所有參數 x264_t *x264_encoder_open(x264_param_t*); //x264_encoder_headers:寫SPS和PPS數據 int x264_encoder_headers(x264_t*, x264_nal_t**, int*); //x264_encoder_encode:編碼一幀圖像 int x264_encoder_encode(x264_t *, x264_nal_t **pp_nal, int *pi_nal,x264_picture_t *pic_in,x264_picture_t *pic_out); //x264_encoder_close:關閉編碼器句柄 void x264_encoder_close(x264_t*);