调用Xvid编码器流程(基于xvid1.1.0)
xvid有兩種編碼方式:single pass和twopass
? single pass模式編碼簡單,速度也快,但最終效果不如twopass。
? twopass就是視頻壓制需要經(jīng)過兩次編碼,分別為twopass-1st pass(簡稱1pass)和twopass-2nd pass(簡稱2pass)
? 1pass時,編碼器會用最高質(zhì)量編碼采集可供第2次運(yùn)算參考的畫面信息,而在2 pass時。編碼器會根據(jù)第一次壓縮獲得的信息和用戶指定的文件大小,自動分配比特率,使需要高流量的運(yùn)動畫面分配到更多的空間,更高的比特率來保證畫面質(zhì)量。相對的,對于那些不包含太多運(yùn)動信息的靜態(tài)畫面則用較低的比特率。追求畫質(zhì)的朋友當(dāng)然會選擇這種方式,但運(yùn)算比single pass更費(fèi)時。
接下來介紹一些基本概念:
? Q值——量化值,它被用來描述1幀的質(zhì)量,每幀都有一個Q值,取值范圍在1-31之間。Q值越小,畫質(zhì)越好,比特率越大
? I-frame——關(guān)鍵幀,常被縮寫為IF。關(guān)鍵幀是構(gòu)成一個幀組的第一幀。IF保留了一個場景的所有信息
? P-frame——未來單項(xiàng)預(yù)測幀,縮寫為PF,只儲存與之前一個已解壓畫面的差值
? B-frame——雙向預(yù)測幀,縮寫為BF,除了參考之前解壓的畫面以外,也會參考后一幀的畫面信息
?
編碼流程:
?
?? 各變量的設(shè)置:創(chuàng)建xvid_enc_frame_t和xvid_enc_stats_t,分別用于傳入?yún)?shù)和統(tǒng)計(jì)編碼結(jié)果。
具體過程:
設(shè)置傳入圖像數(shù)據(jù)和圖像色彩空間
設(shè)置傳出的碼流
設(shè)置vol的標(biāo)志
設(shè)置幀的編碼類型
設(shè)置量化因子
設(shè)置運(yùn)動估計(jì)算法集合
設(shè)置vop的標(biāo)志
編碼器提供的函數(shù)
1,? xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);
含義:根據(jù)cpu的特性使用相應(yīng)匯編優(yōu)化的函數(shù)
?
2,? xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);
含義:初始化編碼器。
具體過程:
創(chuàng)建編碼器句柄,并根據(jù)傳入的參數(shù)設(shè)置各變量的值,并且分配要使用的內(nèi)存,用于存放重建幀,參考幀(1/2像素精度)。以及各種臨時變量。并且做好碼率控制的初始化。
?
3,? xvid_encore(enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame, &xvid_enc_stats);
目的:編碼一幀
具體過程:
{
初始化寫碼流。
如果有必要,轉(zhuǎn)換色彩空間,并且把原始圖像拷貝到有邊框的圖像空間,但是沒有擴(kuò)展邊框。
將重建幀交換成參考幀
從幀隊(duì)列中獲取當(dāng)前幀
設(shè)置Encoder結(jié)構(gòu)體的current結(jié)構(gòu)體的vol_flags,vop_flags,motion_flags,fcode,bcode和quant字段。
調(diào)用call_plugins,在里面調(diào)用rc_single_before做碼率控制的初始化,以及對current結(jié)構(gòu)體的其他變量進(jìn)一步設(shè)置
通過幀號或者MEanalysis函數(shù)分析來確定編碼類型,并且根據(jù)用戶的設(shè)置作修正。
MEanalysis的原理是,如果某個宏塊的殘差的sad大于該宏塊的平均值的偏離,那么使用intra方式,否則使用inter方式,然后對這些宏塊進(jìn)行統(tǒng)計(jì),得到整幀的編碼方式。
?
如果編碼類型是I_VOP
{
設(shè)置Encoder->mbParam->vol_flags
設(shè)置Encoder->mbParam.par
根據(jù)vol_flags設(shè)置vop_flags
調(diào)用FrameCodeI以I幀的方式編碼
調(diào)用call_plugins,在里面調(diào)用rc_single_after,進(jìn)行碼率控制。
}
?
如果編碼類型是P_VOP
{
用mbParam.vol_flags固定住pEnc->current->vol_flags
調(diào)用FrameCodeP以P幀的方式編碼
調(diào)用call_plugins,在里面調(diào)用rc_single_after,進(jìn)行碼率控制。
}
}// xvid_encore
?
4, static int FrameCodeI(Encoder * pEnc, Bitstream * bs)
目的:將一幀圖像編碼成一個I幀
具體過程:
以XVID_PLG_FRAME參數(shù)調(diào)用call_plugins,該函數(shù)目前的作用是設(shè)置dquant,可以在該函數(shù)中設(shè)置最好質(zhì)量。
調(diào)用SetMacroblockQuants,為每個宏塊設(shè)置量化因子,所以也可以在這里設(shè)置最好質(zhì)量
調(diào)用BitstreamWriteVolHeader,寫vol
調(diào)用set_timecodes,設(shè)置時間編碼。
調(diào)用BitstreamPad,填充bit至字節(jié)對齊
調(diào)用BitstreamWriteVopHeader,填寫vop頭
?
依次讀取每一個宏塊,進(jìn)行編碼
{
調(diào)用CodeIntraMB設(shè)置編碼模式為intra,將所有和運(yùn)動有關(guān)的變量設(shè)為0
調(diào)用MBTransQuantIntra進(jìn)行變換編碼
{
調(diào)用MBTrans8to16將像素的表示方法從8bit擴(kuò)大到16bit
調(diào)用MBfDCT對像素進(jìn)行變換編碼
調(diào)用MBQuantIntra對dct系數(shù)進(jìn)行intra方式的量化
調(diào)用MBDeQuantIntra對dct系數(shù)進(jìn)行intra方式的反量化
調(diào)用MBiDCT將恢復(fù)的dct系數(shù)進(jìn)行反變換
調(diào)用MBTrans16to8將恢復(fù)的16bit像素飽和到8bit,組成重建宏塊
}//MBTransQuantIntra
?
調(diào)用MBPrediction作acdc預(yù)測
{
調(diào)用get_dc_scaler函數(shù)得到量化系數(shù)
調(diào)用predict_acdc得到預(yù)測方向以及在該預(yù)測方向上的和當(dāng)前塊的同一量化水平的預(yù)測值
調(diào)用calc_acdc_bits以確定是只使用DC預(yù)測,還是DCAC預(yù)測。原理是分別作DC預(yù)測和DCAC預(yù)測,分別計(jì)算在這2種情況下需要的碼流長度,以確定哪種方式更節(jié)約碼流。
調(diào)用CodeCoeffIntra_CalcBits,用于確定各種方式下的碼流長度
根據(jù)預(yù)測模式的不同,恢復(fù)成相應(yīng)的系數(shù)
最后計(jì)算該宏塊的cbp
}//MBPrediction
?
調(diào)用MBCoding將宏塊編制成碼流
{
調(diào)用CodeBlockIntra將intra宏塊編制成碼流
{
編碼mcbpc
編碼ac預(yù)測標(biāo)記
編碼cbpy
對于6個塊里的每個塊
首先編碼DC系數(shù)
調(diào)用CodeCoeffIntra對剩下的63個系數(shù)進(jìn)行編碼
}//CodeBlockIntra
}//MBCoding
?
}//依次讀取每一個宏塊,進(jìn)行編碼
?
填充bit,直到字節(jié)對齊
?
?
5, static int FrameCodeP(Encoder * pEnc, Bitstream * bs)
含義:將一幀圖片編碼成P幀
具體過程:
{
如果參考幀還沒有設(shè)置邊框,那么就調(diào)用image_setedges設(shè)置邊框
如果需要半像素運(yùn)動估計(jì),那么就調(diào)用image_interpolate進(jìn)行插值
將一幀填充邊框后的參考幀,分成8*8的小塊,對于每個小塊進(jìn)行插值,如下:
調(diào)用interpolate8x8_halfpel_h進(jìn)行水平插值
調(diào)用interpolate8x8_halfpel_v進(jìn)行垂直插值
調(diào)用interpolate8x8_halfpel_hv進(jìn)行對角線插值
用參數(shù)XVID_PLG_FRAME調(diào)用call_plugins,該函數(shù)目前的作用是設(shè)置dquant,可以在該函數(shù)中設(shè)置最好質(zhì)量。
調(diào)用SetMacroblockQuants,為每個宏塊設(shè)置量化因子,所以也可以在這里設(shè)置最好質(zhì)量
調(diào)用MotionEstimation做運(yùn)動估計(jì)
{
使用MotionFlags變量保存要使用的運(yùn)動算法集合
使用skip_thresh保存要達(dá)到skip模式的閥值
使用Data保存運(yùn)動估計(jì)要用到的相應(yīng)變量
對于每個宏塊,依次執(zhí)行如下操作
{
調(diào)用sad16v計(jì)算本宏塊與參考幀對應(yīng)位置宏塊的亮度的殘差,將其保存在pMB->sad16中,并按照4個塊的方式分別存放pMB->sad8[0-3]中
用sad00記錄最大亮度塊殘差的4倍
如果還需要考慮色差塊的因素
調(diào)用sad8兩次,分別計(jì)算u分量和v分量的殘差,都加入pMB->sad16中,并且也加入sad00中
如果該宏塊的量化差值為0,并且sad00又沒有超過skip模式的閥值
如果已經(jīng)考慮了色差因素,或者使用xvid_me_SkipDecisionP確認(rèn)符合skip模式。
調(diào)用ZeroMacroblockP將其編碼為skip模式,并置標(biāo)記pMB->mode = MODE_NOT_CODED
根據(jù)采用的運(yùn)動估計(jì)算法不同,做相應(yīng)的設(shè)置
調(diào)用SearchP做該宏塊的運(yùn)動估計(jì)
{
確定是否使用inter4v模式,并記錄之
調(diào)用get_range確定運(yùn)動搜索的范圍,并記錄在Data中
調(diào)用get_pmvdata2,以獲得左,上,右上的運(yùn)動向量,以及它們對應(yīng)的sad,存入pmv[1-3]和Data->temp[1-3]。然后計(jì)算它們的中值,并且存放于pmv[0],并且把最小的sad存放于Data->temp[0]
設(shè)置Data的當(dāng)前宏塊的yuv字段。設(shè)置Data->RefP[0-5]為參考幀的同一宏塊的整像素y,水平半象素y,垂直半象素y,對角線y,u,v。
設(shè)置Data->lambda16和Data->lambda8,其含義可能是運(yùn)動向量對帶寬的占用折合到sad的值
設(shè)置qpel和方向
如果采用qpel,調(diào)用get_qpmv2計(jì)算用qple方式下的估計(jì)中值,存入ata->predMV;否則,Data->predMV為0。
調(diào)用d_mv_bits計(jì)算mv需要的編碼bit,用于修正pMB->sad16和pMB->sad8[0],并將Data->iMinSAD[0-4]設(shè)置為pMB->sad16和pMB->sad8[0-3],也就是0向量對應(yīng)的各SAD。
如果不采用率失真決策模型,并且不是當(dāng)前幀的第一宏塊,那么使用一種方法設(shè)置閥值threshA,否則閥值threshA為512。
?
調(diào)用PreparePredictionsP,對pmv作進(jìn)一步的設(shè)置,做運(yùn)算前的準(zhǔn)備。
{
設(shè)置pmv[0]為0向量
設(shè)置pmv[1]為中值向量的偶數(shù)值
設(shè)置pmv[2]為參考幀相同位置宏塊的第0塊運(yùn)動向量的偶數(shù)值
如果該宏塊有左邊宏塊,設(shè)置pmv[3]為左邊宏塊的第1塊的運(yùn)動向量的偶數(shù)值,否則為0
如果該宏塊有上面宏塊,設(shè)置pmv[4]為上面宏塊的第2塊的運(yùn)動向量的偶數(shù)值,否則為0
如果該宏塊有右上宏塊,設(shè)置pmv[5]為右上宏塊的第2塊的運(yùn)動向量的偶數(shù)值,否則為0
如果該宏塊有右下宏塊,設(shè)置pmv[6]為參考幀的相同宏塊的右下宏塊的第0塊的運(yùn)動向量的偶數(shù)值,否則為0。
}//PreparePredictionsP
?
如果使用inter4v,設(shè)置CheckCandidate為CheckCandidate16,否則設(shè)置為CheckCandidate16no4v
?
逐一檢查mpv[1-6]這六個最可能運(yùn)動向量,如果發(fā)現(xiàn)他們與以前的運(yùn)動不同,就調(diào)用CheckCandidate做運(yùn)動估計(jì),過程如下:
{
檢查要做運(yùn)動估計(jì)的運(yùn)動向量是否越界
通過該運(yùn)動向量獲得所指向數(shù)據(jù)塊的指針
調(diào)用sad16v,記錄下4個8*8塊的SAD值,存入data->temp[0-3]中,并將他們的和存入臨時變量sad中。
對sad和data->temp[0]做基于運(yùn)動向量的修正。
如果要考慮色差因素,調(diào)用xvid_me_ChromaSAD計(jì)算額外的SAD,累加至sad中。
如果sad小于data->iMinSAD[0],那么設(shè)置data->iMinSAD[0],data->currentMV[0],和data->dir。注意,此時的data->dir記錄的不是鉆石搜索的方向,而是當(dāng)前向量是pmv數(shù)組的第幾個元素。
逐一檢查data->temp[0-3],如果他們小于data->iMinSAD[1-4],那么修改data->iMinSAD[1-4]和data->currentMV[1-4]
}//CheckCandidate
?
如果當(dāng)前最優(yōu)運(yùn)動向量,即Data->iMinSAD[0],小于threshA?或者當(dāng)前最優(yōu)運(yùn)動向量等于參考幀相同位置宏塊的運(yùn)動向量,并且對應(yīng)的SAD值又比他的小?
就不再做inter4v的搜索
否則,就做inter4v的搜索
{
使用make_mask逐一檢查存放于pmv的所有運(yùn)動向量,察看是否位于欲搜索的鉆石形的頂點(diǎn)。如果是,則在mask變量中標(biāo)記之。
根據(jù)MotionFlags確定使用的搜索函數(shù),根據(jù)當(dāng)前設(shè)置,MainSearchPtr = xvid_me_AdvDiamondSearch
調(diào)用xvid_me_AdvDiamondSearch進(jìn)行搜索,過程如下:
{
bDirection既表明了上次嘗試的方向,又表明本次可以嘗試的方向
x,y為鉆石搜索的位置的中心點(diǎn)坐標(biāo)
for(;;)
{
如果可以嘗試左邊,那么調(diào)用CheckCandidate嘗試左邊
如果可以嘗試右邊,那么調(diào)用CheckCandidate嘗試右邊
如果可以嘗試上邊,那么調(diào)用CheckCandidate嘗試上邊
如果可以嘗試下邊,那么調(diào)用CheckCandidate嘗試下邊
如果有更好的方向
{
bDirection = 更好的方向
如果更好的方向是左右方向,那么測試該位置的上下方向
否則,那么測試該位置的左右方向
如果這次又找到了更好的方向
將更好的方向累加到bDirection
將更好的位置存入x,y
}
否則
{
根據(jù)去搜索臨近未搜索的點(diǎn),具體規(guī)則如下:
如果bDirection = = 2,表明搜索方向是趨向右邊的,那么搜索當(dāng)前中心點(diǎn)的右上點(diǎn)和右下點(diǎn)。
如果bDirection = = 1,表明搜索方向是趨向左邊的,那么搜索當(dāng)前中心點(diǎn)的左上點(diǎn)和左下點(diǎn)。
如果bDirection = = 2+4,表明搜索方向是趨向右上的,那么再搜索當(dāng)前中心點(diǎn)的左上點(diǎn),右上點(diǎn)和右下點(diǎn)。
如果bDirection = = 4,表明搜索方向是趨向上邊的,那么搜索當(dāng)前中心點(diǎn)的左上點(diǎn)和右上點(diǎn)。
如果bDirection = = 8,表明搜索方向是趨向下邊的,那么搜索當(dāng)前中心點(diǎn)的左下點(diǎn)和右下點(diǎn)。
如果bDirection = = 1+4,表明搜索方向是趨向左上的,那么再搜索當(dāng)前中心點(diǎn)的左下點(diǎn),左上點(diǎn)和右上點(diǎn)。
如果bDirection = = 2+8,表明搜索方向是趨向右下的,那么再搜索當(dāng)前中心點(diǎn)的左下點(diǎn),左上點(diǎn)和右上點(diǎn)。
如果bDirection = = 1+8,表明搜索方向是趨向左下的,那么再搜索當(dāng)前中心點(diǎn)的左上點(diǎn),左下點(diǎn)和右下點(diǎn)。
否則的話,則認(rèn)為本輪搜索沒有找到更好的點(diǎn),那么再搜索當(dāng)前中心點(diǎn)的左上點(diǎn),左下點(diǎn),右上點(diǎn),右下點(diǎn)。
}
如果沒有找到更好的方向,從函數(shù)中返回
更新bDirection為更好的方向
更新x,y為更好的位置
}//for(;;)
?
}//xvid_me_AdvDiamondSearch
?
如果運(yùn)動估計(jì)算法使用了XVID_ME_EXTSEARCH16,那么
{
設(shè)置startMV = Data->predMV
設(shè)置backupMV為當(dāng)前最佳運(yùn)動向量
如果startMV和backupMV不相等
{
調(diào)用CheckCandidate計(jì)算位置為startMV的SAD
調(diào)用xvid_me_DiamondSearch做以startMV為起點(diǎn)的搜索,過程如下:
{
for(;;)
{
如果可以嘗試左邊,那么調(diào)用CheckCandidate嘗試左邊
如果可以嘗試右邊,那么調(diào)用CheckCandidate嘗試右邊
如果可以嘗試上邊,那么調(diào)用CheckCandidate嘗試上邊
如果可以嘗試下邊,那么調(diào)用CheckCandidate嘗試下邊
如果沒有更好的方向,退出
bDirection = 更好的方向
x,y = 更好的位置
如果更好的方向是左右方向,那么測試該位置的上下方向
否則,那么測試該位置的左右方向
如果這次又找到了更好的方向
{
bDirection += 更好的方向
x,y = 更好的位置
}
}
}//xvid_me_DiamondSearch
?
將這次搜索結(jié)果和上次搜索結(jié)果比較,記錄最佳的SAD和位置。
}//如果startMV和backupMV不相等
?
設(shè)置startMV = {1,1}
設(shè)置backupMV為當(dāng)前最佳運(yùn)動向量
如果startMV和backupMV不相等
{
調(diào)用CheckCandidate計(jì)算位置為startMV的SAD
調(diào)用xvid_me_DiamondSearch做以startMV為起點(diǎn)的搜索,過程如下:
將這次搜索結(jié)果和上次搜索結(jié)果比較,記錄最佳的SAD和位置。
}
}//如果運(yùn)動估計(jì)算法使用了XVID_ME_EXTSEARCH16
}//否則,就做inter4v的搜索
?
如果沒有采用1/4像素運(yùn)動估計(jì)算法
{
如果采用了XVID_ME_HALFPELREFINE16算法
調(diào)用xvid_me_SubpelRefine
按順時針方向8次調(diào)用CheckCandidate16,得到最好的1/2像素位置
}
否則
略
?
如果當(dāng)前SAD足夠小,那么inter4v = 0
如果采用inter4v
{
4次調(diào)用Search8來搜索4個8*8塊的最佳運(yùn)動向量,每一次搜索的規(guī)則如下:
{
如果采用1/4像素運(yùn)動估計(jì),略。否則
調(diào)用get_pmv2取得本塊的中值
計(jì)算第一塊以外快的d_mv_bits
用Data->lambda8修正該塊當(dāng)前的SAD,但是第0塊是不用修正的。
如果使用了XVID_ME_EXTSEARCH8 | XVID_ME_HALFPELREFINE8 | XVID_ME_QUARTERPELREFINE8,那么
{
Data->RefP[0-3] = 參考幀的整像素,水平半象素,垂直半象素,對角線半象素的對應(yīng)宏塊的對應(yīng)塊的起始地址。
Data->Cur = 當(dāng)前幀的當(dāng)前宏塊的當(dāng)前塊的起始地址
利用get_range得到運(yùn)動搜索的范圍
根據(jù)MotionFlags的指示,設(shè)定運(yùn)動估計(jì)MainSearchPtr的算法,當(dāng)前設(shè)置為MainSearchPtr = xvid_me_AdvDiamondSearch。
調(diào)用xvid_me_AdvDiamondSearch做運(yùn)動估計(jì),其中做SAD的函數(shù)是CheckCandidate8,該函數(shù)類似于CheckCandidate16
如果不采用1/4像素運(yùn)動估計(jì),并且又采用了XVID_ME_HALFPELREFINE8,那么調(diào)用xvid_me_SubpelRefine
按順時針方向8次調(diào)用CheckCandidate8,得到最好的1/2像素位置
如果采用了1/4像素運(yùn)動估計(jì),略
}// XVID_ME_EXTSEARCH8 | XVID_ME_HALFPELREFINE8 | XVID_ME_QUARTERPELREFINE8
?
如果采用1/4運(yùn)動估計(jì)
略
否則
記錄pMB->pmvs[block] = 當(dāng)前找到的最佳位置與預(yù)測位置的差值
?
將這次的搜索存入相應(yīng)OldData的字段,以及pMB的相應(yīng)字段
}// Search8
如果考慮色差的因素,并且又不考慮率失真算法
{
根據(jù)是否采用1/4像素運(yùn)動估計(jì)算出色差的運(yùn)動向量
計(jì)算u,v的SAD,將其作為Data->iMinSAD[1]的修正
}
} //如果采用inter4v
否則,Data->iMinSAD[1]為足夠大的值
}//SearchP
?
調(diào)用ModeDecision_SAD確定該宏塊的類型
判斷該宏塊要采取的編碼方式,MODE_INTER,MODE_INTER4V,MODE_NOT_CODED,MODE_INTRA
調(diào)用motionStatsPVOP做一些統(tǒng)計(jì)工作
具體過程略
}//對于每個宏塊,依次執(zhí)行如下操作
做一些最后的設(shè)置
}//MotionEstimation
?
調(diào)用set_timecodes設(shè)置時間戳
調(diào)用BitstreamWriteVopHeader寫VOP頭
具體過程略
?
對于每一個宏塊,依次執(zhí)行如下操作
{
如果該宏塊的編碼模式是MODE_INTRA或者MODE_INTRA_Q
{
調(diào)用CodeIntraMB設(shè)置編碼模式為intra,將所有和運(yùn)動有關(guān)的變量設(shè)為0
調(diào)用MBTransQuantIntra進(jìn)行變換編碼
調(diào)用MBCoding將該宏塊編制成碼流
Continue
}
?
調(diào)用MBMotionCompensation做運(yùn)動補(bǔ)償
{
如果編碼模式是MODE_NOT_CODED
用參考幀的相應(yīng)宏塊替代當(dāng)前幀的當(dāng)前宏塊
Return
?
如果編碼模式是MODE_NOT_CODED或者MODE_INTER或者MODE_INTER_Q
{
如果mb->mcsel不為0
做GMC的處理
Return
計(jì)算運(yùn)動向量dx,dy
調(diào)用compensate16x16_interpolate進(jìn)行運(yùn)動補(bǔ)償
{
如果采用1/4像素運(yùn)動估計(jì)
略
否則,調(diào)用get_ref計(jì)算用于運(yùn)動補(bǔ)償?shù)膮⒖己陦K的指針
調(diào)用4次transfer_8to16sub做亮度塊的運(yùn)動補(bǔ)償,使得臨時數(shù)組里存放的是殘差,而原始圖像里存放的是參考快的數(shù)據(jù)。
}//compensate16x16_interpolate
計(jì)算出用于色差運(yùn)動補(bǔ)償?shù)?span style="font-family:Times New Roman">dx,dy
}//MODE_NOT_CODED或者MODE_INTER或者MODE_INTER_Q
?
否則,那就是MODE_INTER4V
{
根據(jù)是否使用1/4像素運(yùn)動估計(jì),計(jì)算出4個色度塊的運(yùn)動向量
以這4個運(yùn)動向量為參數(shù),調(diào)用4次compensate8x8_interpolate ,該操作類似于compensate16x16_interpolate,不同在于一次只計(jì)算一個塊。
計(jì)算出用于色差運(yùn)動補(bǔ)償?shù)?span style="font-family:Times New Roman">dx,dy
}
?
調(diào)用CompensateChroma計(jì)算色差塊的運(yùn)動補(bǔ)償
{
調(diào)用interpolate8x8_switch2計(jì)算出u的插值
調(diào)用interpolate8x8_halfpel_v或者interpolate8x8_halfpel_h或者interpolate8x8_halfpel_hv做實(shí)際的插值操作,或者直接返回
調(diào)用transfer_8to16sub_c做u份量的運(yùn)動補(bǔ)償
?
調(diào)用interpolate8x8_switch2計(jì)算出v的插值
調(diào)用interpolate8x8_halfpel_v或者interpolate8x8_halfpel_h或者interpolate8x8_halfpel_hv做實(shí)際的插值操作,或者直接返回
調(diào)用transfer_8to16sub_c做v份量的運(yùn)動補(bǔ)償
}//CompensateChroma
?
}//MBMotionCompensation
?
如果需要編碼,那么用MBTransQuantInter進(jìn)行編碼,并把結(jié)果返回給pMB->cbp
{
調(diào)用MBfDCT進(jìn)行宏塊變換編碼
調(diào)用6次fdct
?
調(diào)用MBQuantInter進(jìn)行量化
{
對于宏塊里的每一塊
{
調(diào)用quant_h263_inter進(jìn)行量化
如果在量化后,前三個系數(shù)為0,并且系數(shù)的絕對值之和小于閥值,那么標(biāo)記該塊為全0塊,將標(biāo)記存入cbp。否則,標(biāo)記為非全0塊,也將標(biāo)記存入cbp
}
}//MBQuantInter
?
調(diào)用MBDeQuantInter反量化
{
確定要使用的反量化函數(shù)
對于六個塊里的每個塊,如果cbp表示許可,都調(diào)用dequant_h263_inter反量化
}//MBDeQuantInter
?
調(diào)用MBiDCT做反離散余弦變換
對于六個塊里的每個塊,如果cbp表示許可,都調(diào)用idct_int32反量化
?
調(diào)用MBTrans16to8將恢復(fù)出的殘差構(gòu)成重建圖像
{
確定具體執(zhí)行的函數(shù),分為transfer_16to8copy和transfer_16to8add
找到該宏塊的y,u,v分量起始地址
對于六個塊里的每個塊,如果cbp表示許可,調(diào)用相應(yīng)得函數(shù)執(zhí)行重建。
}// MBTrans16to8
}//MBTransQuantInter
?
如果無殘差,并且編碼方式為MODE_INTER,并且?guī)绞绞?span style="font-family:Times New Roman">P幀,并且向量2分量都為0,那么可以考慮skip模式
如果可以考慮skip模式,則做進(jìn)一步檢驗(yàn),如果檢驗(yàn)通過,那么
{
編碼模式為MODE_NOT_CODED,并且在碼流里做標(biāo)記
Continue
}
?
調(diào)用MBCoding將這個宏塊寫入碼流
{
寫入非NOT_CODED標(biāo)記
調(diào)用CodeBlockInter寫入碼流
{
編碼mcbpc
編碼cbpy
調(diào)用CodeVector編碼運(yùn)動向量
對六個塊,如果cbp只是需要編碼,調(diào)用CodeCoeffInter進(jìn)行編碼
}//CodeBlockInter
}// MBCoding
?
}//對于每一個宏塊,依次執(zhí)行如下操作
?
更新fcode
為下一幀的編碼做簡單的更新設(shè)置
統(tǒng)計(jì)該幀編碼長度
}// FrameCodeP
?創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎
總結(jié)
以上是生活随笔為你收集整理的调用Xvid编码器流程(基于xvid1.1.0)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Swift4.0复习特性、编译标志和检查
- 下一篇: 2019FME博客大赛——FME在室内地