偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

代碼與標準如何對應(yīng)

開發(fā) 項目管理
今天再以 X264 的幀內(nèi)編碼為例讓大家體會一下讀代碼時該如何與標準對應(yīng)。此貼是帖子“如何閱讀代碼”的延續(xù),因此采用的代碼與編譯環(huán)境設(shè)置與其一樣,此處不再贅述。

總是有人說自己把代碼和標準對應(yīng)不起來。其實是因為你要么不知道標準各個章節(jié)講的什么,要么不知道代碼中各個函數(shù)的功能,或者兩者都不知道。今天再以 X264 的幀內(nèi)編碼為例讓大家體會一下讀代碼時該如何與標準對應(yīng)。此貼是帖子“如何閱讀代碼”的延續(xù),因此采用的代碼與編譯環(huán)境設(shè)置與其一樣,此處不再贅述。

上貼說過 Encode_frame 函數(shù)包含最核心的編碼代碼,那么我們現(xiàn)在就 F11 進去看看。遇到的第一個函數(shù)是 x264_encoder_encode,再 F11 進去,執(zhí)行到 x264_reference_update,它在干什么呢?顧名思義猜測一定是更新幀間參考要用到的一些內(nèi)存空間,因為我們現(xiàn)在還沒有編碼,所以 F11 進去后沒執(zhí)行什么操作就出來了。

繼續(xù) F10,執(zhí)行到 x264_frame_pop_unused。F11 跟進,然后 F10,發(fā)現(xiàn)它走了 x264_frame_new 的分支(x264_frame_pop 分支干什么用的呢?暫時先別管。跟著流程走,管多了就迷茫了),F(xiàn)11 跟進 x264_frame_new 發(fā)現(xiàn)通篇都是對變量結(jié)構(gòu)體指針 frame 里的成員變量執(zhí)行 CHECKED_MALLOC,由此我們可以初步判斷它是在為幀結(jié)構(gòu)體分配內(nèi)存空間。

step out 跳出 x264_frame_pop_unused,F(xiàn)10 到 x264_frame_copy_picture,F(xiàn)11 進去讀讀代碼我們就知道這個函數(shù)的功能是將待編碼圖像從 pic_in 復制到 fenc->plane。繼續(xù) F10,到了 x264_frame_push,通過閱讀該函數(shù)的代碼我們知道它的功能是將當前幀結(jié)構(gòu)體從 fenc 移到 h->frames.next 中。后面的函數(shù) x264_frame_init_lowres、x264_adaptive_quant_frame、x264_encoder_frame_end 都未被執(zhí)行。既然沒被執(zhí)行,那我們現(xiàn)在暫時就不管它們。

F10 到 x264_stack_align( x264_slicetype_decide, h ); x264_stack_align 顧名思義無非就是平臺優(yōu)化方面考慮的對齊操作,因此這里我們要關(guān)心的是函數(shù) x264_slicetype_decide,F(xiàn)11 我們會發(fā)現(xiàn)進不到 x264_slicetype_decide 里。怎么辦呢?見下面第一個截圖,將光標點到 x264_slicetype_decide 上,點鼠標右鍵選擇 go to definition,然后先在里面的第一行代碼下斷點(見下面第二個截圖),然后再按 F10 就可以進入到 x264_slicetype_decide 函數(shù)了。該函數(shù)顧名思義是來決定當前 slice 的編碼類型的,即到底是 I 片還是 P 片或 B 片。通過瀏覽其代碼,我們也會發(fā)現(xiàn)代碼所做也正是這樣。

1.GIF

2.GIF

step out 跳出 x264_slicetype_decide,繼續(xù) F10 執(zhí)行到 x264_frame_push,這里實際要執(zhí)行兩個函數(shù),因為 x264_frame_push 的第二個參數(shù)是函數(shù) x264_frame_shift,所以會先執(zhí)行它。F11 首先進入的就是 x264_frame_shift,然后 step out 跳出 x264_frame_shift,繼續(xù) F11 就進入了 x264_frame_push,通過閱讀這兩個簡短的函數(shù)的代碼,我們知道它們執(zhí)行的操作是將當前編碼幀結(jié)構(gòu)體從 h->frames.next 移到 h->frames.current。

繼續(xù) F10,又到了一個 x264_frame_shift 函數(shù),F(xiàn)11 進去通過閱讀代碼我們可以知道該函數(shù)的功能將當前幀結(jié)構(gòu)體從 h->frames.current 移到 h->fenc(我有點奇怪,為什么 X264 要這么麻煩地把一個變量移來移去呢?一次搞定不行么?)。繼續(xù) F10,到了 x264_reference_reset,其功能顧名思義,也有英文注釋,具體有什么用,現(xiàn)在我還不知道,暫時不管吧。

繼續(xù) F10,到了 x264_reference_build_list,顧名思義,參考列表構(gòu)建,在 JM 里叫做參考列表初始化(JM86 對應(yīng)的函數(shù)是 init_lists)。參考列表初始化的作用即構(gòu)建幀間編碼圖像所需要用到的參考圖像列表。那么如何初始化呢?如果大家記得 H.264 標準的各個章節(jié)的功能,那么就該知道 200503 版的 8.2.4 小節(jié)正是講的這部分內(nèi)容。這樣這個函數(shù)就與標準的內(nèi)容對應(yīng)起來了。至于通過代碼是如何實現(xiàn)的,先看懂了標準的這個部分再來讀這個函數(shù)的代碼吧。

繼續(xù) F10,到了 x264_ratecontrol_start,顧名思義進行碼率控制的一些準備工作。

繼續(xù) F10,到了 x264_slice_init,顧名思義片初始化,做了哪些工作呢?F11 進去執(zhí)行了分支 x264_slice_header_init,通過瀏覽其代碼,我們發(fā)現(xiàn)通篇都是對結(jié)構(gòu)體指針 sh 內(nèi)的成員變量的賦值操作。后面的 x264_macroblock_slice_init 函數(shù)在干什么,大家自己 F11 進去看,看不懂沒關(guān)系,反正就是給一些變量賦初值嘛。繼續(xù) F10,到了 bs_init,顧名思義是對碼流相關(guān)的變量進行初始化,因為 bs 就是 bit stream 嘛。

繼續(xù) F10,到了 if( i_nal_type == NAL_SLICE_IDR && h->param.b_repeat_headers ),注意前面的英文注釋 /* Write SPS and PPS */,意思就是這里在向碼流中寫 SPS 和 PPS。這里的三組函數(shù),顧名思義第一組是在寫 SEI、第二組是在寫 SPS、第三組是在寫 PPS。那么如何寫碼流呢?當然是要遵循語法表了。下面以寫 SPS 為例簡要說明一下,如果大家記得 H.264 標準的各個章節(jié)的功能,那么就該知道 200503 版的 7.3.2.1 小節(jié)就是 SPS 語法表。因為 7.3.2.1 規(guī)定了 SPS 在碼流中的第一個語法元素是 profile_idc,因此當我們 F11 進入 x264_sps_write 的時候會發(fā)現(xiàn)該函數(shù)第一行代碼正是在寫 sps->i_profile_idc,標準規(guī)定 SPS 第二個語法元素是 constraint_set0_flag,因此該函數(shù)的第二行代碼就是在寫 sps->b_constraint_set0,其他同理。這里說的是寫的順序,那么寫的方式是什么呢?H.264 中的熵編碼方式細分起來有很多,每個語法表的最后一列 descriptor 規(guī)定的就是對應(yīng)的語法元素采用哪種熵編碼方法。例如:profile_idc 是 u(8),因此它采用 8 位無符號整數(shù)編碼;constraint_set0_flag 是 u(1),因此它采用 1 比特無符號整數(shù)編碼。各種熵編碼方法在 200503 版 7.2 小節(jié)最后都有說明,此處不再贅述。好了,我們知道了各個語法元素采用什么方式編碼,自然也就知道了代碼中各個熵編碼函數(shù)對應(yīng)的是什么編碼方式。例如:對 profile_idc 編碼采用的是 bs_write 函數(shù),當然這個函數(shù)的功能就是無符號熵編碼了,對 i_id 編碼采用的是 bs_write_ue 函數(shù),當然這個函數(shù)的功能就是 ue(v)——無符號哥倫布編碼。其他同理。其實這些我在帖子“ 如何讀標準和代碼”中已經(jīng)講過了。

順便提一下,對碼流的讀寫操作都要依據(jù)語法表所定義的語法元素順序和熵編碼類型。上面講的是編碼的具體例子,解碼的具體例子我以前用 JM 講過,參考帖子“如何結(jié)合標準看JM代碼(JM86)”。 好了,繼續(xù) F10,到了 x264_slices_write。F11 進入,再 F10,到了 x264_stack_align( x264_slice_write, h );我們關(guān)心的是 x264_slice_write,進入該函數(shù),方法在上面已經(jīng)說過了。x264_slice_write 第一個函數(shù)為系統(tǒng)函數(shù) memset,下一個為 x264_nal_start,其功能看下代碼就知道是在設(shè)置將要寫入碼流的 NALU 的第一個字節(jié)的值。第二個函數(shù) x264_slice_header_write 顧名思義是在向碼流中寫入片頭。如果大家記得 H.264 標準的各個章節(jié)的功能,那么就該知道 200503 版的 7.3.3 小節(jié)就是片頭的語法表。寫碼流的過程與上面 SPS 的過程同理,此處不再贅述。

F10 到了 while 循環(huán),顧名思義根據(jù) while 循環(huán)的循環(huán)條件猜測一下該 while 循環(huán)的功能,肯定就是循環(huán)對整個圖像的每個宏塊一次編碼了。要驗證一下猜測很簡單,在 while 循環(huán)體的第一行下斷點,按一次 F5 就觀察一下 mb_xy 變量的值的變化情況。另外還有個信息說明了這一點,h->sh.i_last_mb 變量的值剛好等于待編碼圖像的總宏塊數(shù)。

F10 到了 x264_fdec_filter_row,顧名思義猜測該函數(shù)的功能是去塊濾波。如果大家記得 H.264 標準的各個章節(jié)的功能,那么就該知道 200503 版的 8.7 小節(jié)正是講的這部分內(nèi)容。要讀懂這個函數(shù)的代碼就先學習一下 8.7 小節(jié)吧。

F10 到了 x264_macroblock_cache_load,通過瀏覽代碼我們知道是在對一些變量賦值,各個變量的含義顧名思義。這也屬于編碼前的準備工作。 繼續(xù) F10 到了 x264_macroblock_analyse,看見英文注釋了吧?不用我們顧名思義就知道它的功能了,是在進行模式選擇。F11 進入該函數(shù)。第一個被調(diào)用的函數(shù)是 x264_ratecontrol_qp,顧名思義獲取當前宏塊 QP。第二個被調(diào)用的函數(shù)是 x264_mb_analyse_init,F(xiàn)11 進去后發(fā)現(xiàn)只有非 I 片才進行一些操作,那暫時就不管它。

F10 到了 x264_mb_cache_fenc_satd,F(xiàn)11 進去。一開始是個 4*4 的雙重循環(huán)。我們現(xiàn)在是在對一個宏塊進行操作,這里又出現(xiàn) 4*4 的循環(huán),那么很明顯了這個雙重循環(huán)肯定是在計算每個 4*4 的塊,下面的 2*2 的雙重循環(huán)肯定是在計算 8*8 的塊。因為宏塊的尺寸是 16*16 嘛,寬高分成 4 份不正好是 4*4,分成 2 份不正好是 8*8 么?做視頻的人應(yīng)該對 4、8、16 等常用的數(shù)字敏感。先分析第一個 4*4 的雙重循環(huán)。注意,for 循環(huán)里的 h->pixf.satd 和 h->pixf.sad 都是函數(shù)指針,因此要用 F11 跟進。h->pixf.satd 的兩個輸入是 zero 和 fenc,跟進之后的函數(shù) pixel_satd_wxh 在計算他們之差,然后作 Hadamard 變換,然后計算 SATD。由此可以猜測 fenc 里存放的是原始待編碼宏塊(到底是不是呢?讀者自己反回去找到 h->mb.pic.p_fenc[0] 被賦值的地方看看就知道了)。后面代碼的功能類似了,不重復敘述。總的來說,x264_mb_cache_fenc_satd 這個函數(shù)就是計算原始待編碼宏塊 4*4 和 8*8 的 STAD。算來做什么?暫時還不知道。

step out,跳出 x264_mb_cache_fenc_satd 函數(shù),繼續(xù) F10,到了 x264_mb_analyse_intra,F(xiàn)11 進入。F10 到了 predict_16x16_mode_available,顧名思義并結(jié)合該函數(shù)代碼,可以確定它是在檢查當前宏塊有幾種可用的 16*16 幀內(nèi)預測模式。繼續(xù) F10 到了 for 循環(huán) for( i = 0; i < i_max; i++ ),其循環(huán)條件 i_max 是函數(shù) predict_16x16_mode_available 的返回值,那么很顯然這個 for 循環(huán)是在循環(huán)計算可用預測模式了。繼續(xù) F10,進循環(huán)體到了 h->predict_16x16[i_mode],這又是個函數(shù)指針,顧名思義并結(jié)合改函數(shù)代碼,可以確定它是在取得 16*16 塊當前預測模式下的幀內(nèi)預測塊。如果大家記得 H.264 標準的各個章節(jié)的功能,那么就該知道 200503 版的 8.3.3 小節(jié)正是講了 16*16 塊的各種預測模式下如何進行幀內(nèi)預測的。要讀懂這個函數(shù)的代碼就先學習一下 8.3.3 小節(jié)吧。繼續(xù) F10,到了 h->pixf.mbcmp[PIXEL_16x16],又是個函數(shù)指針,其功能大家自己跟進吧。該 for 循環(huán)完成后就把 16*16 塊的最佳預測模式計算出來并存儲起來了。

繼續(xù) F10,到了幀內(nèi) 4*4 的預測模式選擇部分。for 循環(huán) for( idx = 0;; idx++ ),idx 是什么?因為這是幀內(nèi) 4*4 預測,所以我們很自然應(yīng)該聯(lián)想到 idx 就應(yīng)該是 16 個 4*4 塊的編號,這個決定了 16 個 4*4 塊的處理順序,這個順序可不是亂來的哦,200503 版標準/圖 6-10 對順序做了規(guī)定。繼續(xù) F10,到了 x264_mb_predict_intra4x4_mode 顧名思義并結(jié)合該函數(shù)代碼可以確定它是在獲得最可能預測模式,如果大家記得 H.264 標準的各個章節(jié)的功能,那么就該知道 200503 版的 8.3.1.1 小節(jié)正是講的這部分內(nèi)容。要讀懂這個函數(shù)的代碼就先學習一下 8.3.1.1 小節(jié)吧。繼續(xù) F10 到了 predict_4x4_mode_available 跟上面 16*16 塊類似,功能顧名思義就不多說了。繼續(xù) F10,進入第二個 for 循環(huán) for( ; i<i_max; i++ ),一看就知道該 for 循環(huán)跟上面 16*16 塊同理是在計算當前 4*4 塊的最佳預測模式。繼續(xù) F10,進入循環(huán)體到了 h->predict_4x4[i_mode] 顧名思義并結(jié)合該函數(shù)代碼可以確定它是在取得當前 4*4 塊在當前可用預測模式下的幀內(nèi)預測塊,如果大家記得 H.264 標準的各個章節(jié)的功能,那么就該知道 200503 版的 8.3.1.2 小節(jié)正是講的這部分內(nèi)容。要讀懂這個函數(shù)的代碼就先學習一下 8.3.1.2 小節(jié)吧。繼續(xù) F10,到了 h->pixf.mbcmp[PIXEL_4x4],也跟上面 16*16 塊類似,功能顧名思義。

繼續(xù) F10,第二個 for 循環(huán)執(zhí)行完后就把當前 4*4 塊的最佳預測模式計算出來并存儲起來了,到了函數(shù)指針 h->predict_4x4[a->i_predict4x4[idx]],很顯然是在取得當前 4*4 塊的最佳預測模式下的預測塊了。算來干什么?從 H.264 幀內(nèi)宏塊編碼的原理上我們知道幀內(nèi)預測要以相鄰塊的重建值為參考,不先計算預測塊,殘差從哪里來?不得到殘差,又哪里得到重建呢?(所以這里也體現(xiàn)了,讀 代碼前要對編碼原理和框架熟悉,否則你咋能明白這里為什么要取得預測塊呢?)。繼續(xù) F10,到了 x264_mb_encode_i4x4,顧名思義并聯(lián)想幀內(nèi)編碼原理和框架,我們猜測它是在進行當前 4*4 塊的重建。F11 進去驗證一下我們的猜測是否正確。x264_mb_encode_i4x4 函數(shù)里依次執(zhí)行了 h->dctf.sub4x4_dct、x264_quant_4x4、h->zigzagf.scan_4x4、 h->quantf.dequant_4x4、h->dctf.add4x4_idct,各函數(shù)功能顧名思義,的確驗證了我們對 x264_mb_encode_i4x4 這個函數(shù)的功能的猜測。那么這些函數(shù)為什么要以這些順序調(diào)用呢?因為編碼原理和框架就是這樣(這也再次體現(xiàn)了,讀代碼前要對編碼原理和框架熟悉)。

step out,跳出 x264_mb_analyse_intra 函數(shù),繼續(xù) F10,到了 x264_intra_rd,F(xiàn)11 跟進。繼續(xù) F10,到了函數(shù) x264_analyse_update_cache,顧名思義無法猜測其功能,F(xiàn)11 跟進之后發(fā)現(xiàn)它只調(diào)用了一個函數(shù) x264_mb_analyse_intra_chroma,這個函數(shù)又是什么功能呢?留給讀者自己去跟進吧。step out,跳出 x264_analyse_update_cache 函數(shù),繼續(xù) F10,到了 x264_rd_cost_mb,顧名思義猜測是進行 RDO 模式選擇。這種方法的失真測度通常是使用 SSD,即原始像素與重建像素的誤差平方和。那么如果我們對 x264_rd_cost_mb 的功能猜測正確,其函數(shù)中必然有編碼宏塊的代碼和計算 SSD 的代碼。F11 跟進去驗證我們的猜測,x264_rd_cost_mb 里的確調(diào)用了 x264_macroblock_encode 和 ssd_mb。這兩個函數(shù)是否是在執(zhí)行編碼和計算 SSD 的功能呢?留給讀者自己去驗證吧。提醒一句,X264 在這里用的失真測度不僅僅是 SSD,另外還有什么成分,讀者自己去跟蹤 ssd_mb 函數(shù)。x264_rd_cost_mb 函數(shù)最后執(zhí)行的函數(shù)是 x264_macroblock_size_cavlc,顧名思義是在對當前宏塊進行熵編碼了。為什么要熵編碼,因為 RDO 的率失真準則中要用到編碼比特數(shù)啊。

step out,跳出 x264_rd_cost_mb 函數(shù),后面的代碼不說大家也知道了。step out,跳出 x264_intra_rd 函數(shù),該函數(shù)下面的 6 行代碼(見下圖)的功能大家得弄清楚。因為算了這么多模式,這么多代價,最后編碼到底選哪個模式呢?答案就這里了。


3.GIF

step out,跳出 x264_macroblock_analyse 函數(shù),到了 x264_macroblock_encode,顧名思義并結(jié)合編碼流程可以確定這里調(diào)用這個函數(shù)就是在用最終選定的那個最優(yōu)的模式對當前宏塊進行實際編 碼了。繼續(xù) F10,到了 x264_bitstream_check_buffer,顧名思義猜測是進行寫碼流前的一些準備工作。繼續(xù) F10,到了 x264_macroblock_write_cavlc,顧名思義并聯(lián)想編碼流程,很明顯是在將最后的編碼結(jié)果寫入碼流了。

至此,一個宏塊幀內(nèi)編碼的過程就剖析完了。相信大家看完這么長的帖子之后,應(yīng)該對我以前提出的學習建議中的兩點有了深刻體會:1、讀代碼前一定要熟悉編碼 原理和框架;2、弄清楚標準各個章節(jié)講的什么內(nèi)容。當然這也是怎么看標準,怎么用標準的問題——先很粗略地了解各個章節(jié)是講的什么,等到需要詳細了解其內(nèi) 容時候再去細讀相關(guān)章節(jié)。當然,C 語言功底在讀代碼過程中也是必須的,否則像函數(shù)指針這些東西你都搞不清楚怎么回事。

有了這個實際的例子,切身的體驗,再回頭去看看我和別人以前總結(jié)的學習方法的帖子,相信你會有更深的體會。最后還要說一句:別人不可能為你做所有的事,很多還是要靠自己努力!

原文鏈接:http://www.rosoo.net/a/201308/16715.html

責任編輯:陳四芳 來源: 羅素工作室
相關(guān)推薦

2023-09-04 10:10:47

插件頁面元素

2021-12-03 23:28:11

JavaScript開發(fā)代碼

2021-05-12 14:34:08

大數(shù)據(jù)數(shù)據(jù)標準技術(shù)

2009-03-19 09:53:00

IPTV多媒體網(wǎng)絡(luò)

2010-09-10 10:39:57

2010-09-17 16:25:58

2018-07-31 11:13:30

2011-06-13 15:45:58

WEB標準SEO

2009-09-03 21:05:31

2009-07-03 11:47:00

2011-06-13 16:54:25

WEB標準SEO

2011-03-16 15:34:44

2020-09-04 10:07:19

Google代碼審查

2023-03-03 13:59:24

2015-08-18 09:31:12

圖標AB測試

2020-08-11 10:44:46

智能家居物聯(lián)網(wǎng)IOT

2022-04-21 12:00:13

低代碼平臺組件代碼

2024-09-29 16:04:14

2010-09-08 11:26:02

2015-03-10 10:53:29

點贊
收藏

51CTO技術(shù)棧公眾號