以下通過剖析一些經驗來了解視頻解碼優化
1. 在嵌入式系統中實現MPEG4的視頻解碼
有兩種方法可行
(1)采用ffmpeg(mplayer 的核心就是采用ffmpeg),然后對ffmpeg mp4解碼優化
1).對IDCT匯編化,并優化VLD的實現?? ->inline&匯編化
2).根據ARM9 cache&cache line的大小做MB的分組,使得每次可以同時處理多個MB
? 即對多個MB在一個循環內做VLD--->IDCT-->MC--.......? ->耦合
3).優化關鍵代碼段的內存訪問(MC)??? ->inline&匯編化
4).不要使用FFmpeg內置的img_convert()做yuv2rgb轉換? ->inline&匯編化
5).對解碼庫做ARM指令集優化??? ->體系結構優化
? configured ffmpeg with cpu = ARMV4L would give you a better performance
? If you have IPP,you can enable it, you can obtain huge enhancement
? IPP=Intel? Integrated Performance Primitives intel高性能構件庫(only for xScale)
?
(2)用xvid來做,ffmpeg包含的解碼庫太多,如果你只做MPPEG4解碼,何必用這么復雜的庫.
btw,在嵌入式系統中最好用0.9.2版的xvid。因為1.1.0的版本包含了很多AS的特性,通常在
嵌入式系統中都不需要用,并且也不容易實現。要自己做編碼算法的話,不能總想依賴別人
,最好還是需要自己花功夫去實現和優化。因此我覺得從實際出發的話,XVID0.9.2版的比
1.1.0的好。實際上,通常在主頻400MHz的平臺上,要優化XVID的算法達到CIF實時解碼也還
是很容易的,最多就一個多月
2. 視頻解碼流程對解碼帶來的影響
視頻解碼優化一般代碼量大,而且源代碼往往是從其他地方獲取得到的,所以閱讀比較困難
,更別說優化了,最近在優化realVideo,有幾點心得:
1).閱讀代碼前必須先熟悉流程,抓住關鍵的點,比如視頻解碼不外乎熵解碼,反量化,反變
換,插值,重建,濾波,參考幀插入等。把握住這幾個點,可以將代碼很快分離出來。
2). 分析解碼流程,了解解碼需要的最小buffer是多大,各個buffer 的位寬多大。
3).根據已經知道的流程,跟蹤代碼buffer流向,是否存在多余的內存拷貝。想辦法將buffer
減少,經驗說明,減少buffer帶來的速度上的提升遠大于局部算法的優化。 ->耦合
4).觀察程序結構順序是否合理,不合理的程序結構會導致buffer增大。
這兩天研究視頻解碼順序,發現先插值后做反變換要比先做反變換再做插值效率要高許多,
原因是插值后的位寬是8bits,而往往反變換后是9bits,所以在重建之前要保存插值后的值
要比保存反變換后的值要省一半的空間,這樣在重建時訪問的內存就少很多了。據我了解,
大部分高效率的解碼器都是先插值再反變換,而且變換后馬上做重建,這樣既減少內存使用
,也避免內存訪問抖動太厲害,最終減少緩存不命中。 ->修改解碼流程 耦合
3. cache機制對解碼帶來的影響
先看?http://www.hongen.com/pc/diy/know/mantan/cache0.htm
寫透(直寫式)和寫回(回寫式)有著截然不同的操作,在不同的場合,不同的內存塊使用
不同的回寫策略(如果你的系統可以實現的話)要比使用一種策略要高效得多。具體一點,
對于反復存取的內存塊置成寫回,而把一次寫入而很長時間以后再使用的內存置為寫透,可
以大大提高cache的效率。
第一點很容易理解,第二點就需要琢磨一下了,由于寫透的操作是,當緩存有該地址的數據
時同時更新緩存和主存,當緩存沒有該地址數據直接寫主存,忽略緩存。當該地址的數據很
長時間后才被使用到,那么在使用的時候該數據肯定不在cache中(被替換了),所以不如直
接寫入主存來得直接;
相反,如果使用寫回操作,當 cache中有該地址數據,需要更新該數據,設置dirty位,很長
時間后再使用該數據或被替換的時候才將其刷進主存,這有占了茅坑不拉屎的嫌疑;而當
?cache沒有該地址數據時,情況更糟糕,首先需要將相應的主存數據(一個cache line)導
?入cache,再更新數據,設置dirty位,再等待被刷回內存,這種情況不僅占用了cache的空
?間,還多一次從主存中導入數據的過程,同樣占據總線,開銷很大。至于為什么要先從主存
?中導入數據,是因為cache往主存回寫數據時是按照一個cache line 單位來寫的,但被更新
?的數據可能沒有一個cache line這么多,所以為了保證數據一致性,必須先把數據導入
?cache,更新后再刷回來。
對于很多視頻解碼來說,幀寫入過程是一個一次性的動作,只有在下一次作為參考幀時才會
被使用到,所以幀緩沖內存可以設置為寫透操作,而下一次使用它的時候很可能是作為參考
幀來使用,而作為參考幀不需要反復的存取,只需一次讀操作就可以了,所以效率并不會因
為不經過cache而降低。實驗證明該方法可以使 mpeg4 sp解碼提高20-30%的效率。
相似的內容cache操作的小技巧還有prefetch操作,prefetch操作是將主存的數據導入cache
而期間cpu不需要等待,繼續下一條指令的執行,如果下一條指令也是總線的操作,那么就必
須等待prefetch完成以后再開始。所以,在使用該指令時,在prefetch指令后面插入盡可能
大于一次緩存不命中所需要的clock數對應的指令,那么prefetch與其后面的指令可以并行執
行,從而省去了等待的過程,相當于抵消緩存不命中的損失。當然,如果插入的指令太多而
cache太小,有可能prefetch的數據進入cache 后又被替換掉了,所以,這需要自己去評估。?
->cache優化
4. 總結
IDCT是視頻解碼中關鍵步驟中的第一步,目前一般采用快速算法來做,如chen-wang 算法,
c語言和匯編的效果差別還是比較大的。
對一個8x8的block做idct做變換,如???
??? for (i = 0; i < 8; i++)
???? ??? idct_row (block + 8 * i);
??? for (i = 0; i < 8; i++)
???? ??? idct_col (block + i);
把他匯編后,主要是可以減少存儲器帶寬,提高存儲效率,避免無謂的內存讀寫。
mplayer 在此方面做了很多努力,針對armv4(s3c2440屬于armv4l架構)的相關文件放在
dsputil_arm_s.S文件中。但遺憾的是,它里面有一條指令PLD,cache預取指令2440是不支持
的。PLD指令屬于enhanced DSP指令,在armv4E(E 既代表enhanced DSP)才被支持,因此在我
們orchid上跑的代碼必須注釋掉這條指令,否則編譯不過.再把話題轉回來,在IDCT之前,視
頻壓縮流通過VLD(variable lenght decode)變長解碼得到DCT數據。這部分工作一般是通過
查表來加速性能,所有的編碼表會預先存起來。而取視頻比特流的代碼通常是宏,通過宏的
擴展來達到和匯編同樣的效果。在IDCT后還有關鍵的運動補償和色彩空間轉換兩個步驟。對
運動補償的加速也是通過匯編化,其代碼也同樣放在dsputil_arm_s.S 有必要一提的是在這
部分,如果有SIMD指令將會極大的提高它的速度。
color space轉換是解碼輸出后的最重要的一步。在嵌入式系統中,一般都是采用rgb565既
16bit來表示一個像素的色彩。
一個8x8的block,它的yuv(420格式)表示如下,
??????? YYYYYYYY
??????? YYYYYYYY
??????? YYYYYYYY
??????? YYYYYYYY
??????? UUUUUUUU
??????? VVVVVVVV
注意它的值是8bit的,通過裝換方程計算,可以得到像素值。在實現中通常采用查表來加速
計算,對于每一個Y,U,V都有一個對應表。對于1個320x240的video,共76800像素。如果每
個像素在這個轉換中節省10個cycle,那save下來的cpu還是相當可觀的。
當色彩空間轉換完后,就是通過把這個picture copy到framebuffer的內存里,這里存在一大
片的copy時間。有兩方面可以注意,一是有人實現過把轉換后的內存直接往framebuffer送,
減少最后所需的copy過程,這個idea確實不錯,但是需要一些技巧去實現,二是copy這個過程
本省也是可以加速的,在armv5以上的體系結構里,cpu----cache---memory,其中cache和
memory的寬度是32位,但cpu和cache的bus width確是64位,用32位的成本實現了64位的存儲
器。如果這個能被使用,那么理論上,copy速度可以加倍。在PC機上,一般我們的應用程序會有
fastmemorycopy這個函數,它們是用simd等特殊指令來實現,在armv5上則是通過它的總
線寬度來加速在s3c2440上不可用:( 它是v4架構。
總的來說:
(1).算法級的優化基本用無可用,ffmpeg/mplayer已經實現的相當不錯,除非自己實現一個
新的decoder;
(2).在代碼級,主要是通過關鍵代碼的inline(宏,inline函數)和匯編來加速。這部分在
arm平臺還是有一些潛力可挖
(3).硬件級,在這一層,cpu的體系結構決定指令集、cache的形式和大小等。如指令集是否
有enhanced DSP指令、SIMD指令,cache是否可配置、cache line大小,這些都會影響代碼級
和算法級的優化
(4).系統層優化,之所以把它放在最后一層,是由于它建立在整個系統之上,只有對整個系
統包括硬件和軟件有深刻的理解才能做到。
縱觀優化,其實質是盡可能的去除冗余計算,最大化的利用系統硬件資源。
對于RISC架構的cpu來講,先天不足的就是需要比較大的存儲器帶寬(因為RISC的指令都是基
于寄存器的,必須把操作數都load到內存才能計算),cpu資源被過多的使用在內存的read和
write。
以下面代碼為例,它是解碼輸出后,把yuv空間裝換成rgb空間的一個片斷
000111c :???????
??? 111c:?????? e92d4ff0??????? stmdb?? sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
??? 1120:?????? e1a0a000??????? mov???? sl, r0
??? 1124:?????? e5900038??????? ldr???? r0, [r0, #56]
??? 1128:?????? e1a0c001??????? mov???? ip, r1
??? 112c:?????? e3500004??????? cmp???? r0, #4? ; 0x4
??? 1130:?????? e24dd034??????? sub???? sp, sp, #52???? ; 0x34
??? 1134:?????? e1a00002??????? mov???? r0, r2
??? 1138:?????? e1a01003??????? mov???? r1, r3
??? 113c:?????? 0a00055d??????? beq???? 157c
??? 1140:?????? e59d2058??????? ldr???? r2, [sp, #88]
??? 1144:?????? e3520000??????? cmp???? r2, #0? ; 0x0
??? 1148:?????? d1a00002??????? movle?? r0, r2
??? 114c:?????? da00055b??????? ble???? 1574
??? 1150:?????? e59d3060??????? ldr???? r3, [sp, #96]
??? 1154:?????? e58d1030??????? str???? r1, [sp, #48]
??? 1158:?????? e5933000??????? ldr???? r3, [r3]
??? 115c:?????? e59f2434??????? ldr???? r2, [pc, #1076] ; 1598 <.text+0x1598>
??? 1160:?????? e0213193??????? mla???? r1, r3, r1, r3
??? 1164:?????? e58d3018??????? str???? r3, [sp, #24]
??? 1168:?????? e59d305c??????? ldr???? r3, [sp, #92]
??? 116c:?????? e58d1000??????? str???? r1, [sp]
??? 1170:?????? e5933000??????? ldr???? r3, [r3]
??? 1174:?????? e79a1002??????? ldr???? r1, [sl, r2]
??? 1178:?????? e58d301c??????? str???? r3, [sp, #28]
??? 117c:?????? e5903008??????? ldr???? r3, [r0, #8]
??? 1158:?????? e5933000??????? ldr???? r3, [r3]
??? 115c:?????? e59f2434??????? ldr???? r2, [pc, #1076] ; 1598 <.text+0x1598>
??? 1160:?????? e0213193??????? mla???? r1, r3, r1, r3
??? 1164:?????? e58d3018??????? str???? r3, [sp, #24]
??? 1168:?????? e59d305c??????? ldr???? r3, [sp, #92]
??? 116c:?????? e58d1000??????? str???? r1, [sp]
??? 1170:?????? e5933000??????? ldr???? r3, [r3]
??? 1174:?????? e79a1002??????? ldr???? r1, [sl, r2]
??? 1178:?????? e58d301c??????? str???? r3, [sp, #28]
??? 117c:?????? e5903008??????? ldr???? r3, [r0, #8]
??? 1180:?????? e59c4008??????? ldr???? r4, [ip, #8]
??? 1184:?????? e590e000??????? ldr???? lr, [r0]
??? 1188:?????? e59c2000??????? ldr???? r2, [ip]
??? 118c:?????? e5900004??????? ldr???? r0, [r0, #4]
??? 1190:?????? e59cc004??????? ldr???? ip, [ip, #4]
??? 1194:?????? e58d3014??????? str???? r3, [sp, #20]
??? 1198:?????? e1a011c1??????? mov???? r1, r1, asr #3? ;h_size
??? 119c:?????? e3a03000??????? mov???? r3, #0? ; 0x0
??? 11a0:?????? e58d4010??????? str???? r4, [sp, #16]
??? 11a4:?????? e58d2004??????? str???? r2, [sp, #4]
??? 11a8:?????? e58de020??????? str???? lr, [sp, #32]
??? 11ac:?????? e58d000c??????? str???? r0, [sp, #12]
??? 11b0:?????? e58dc008??????? str???? ip, [sp, #8]
??? 11b4:?????? e58d1028??????? str???? r1, [sp, #40]
??? 11b8:?????? e58d3024??????? str???? r3, [sp, #36]
??? 11bc:?????? e1a08003??????? mov???? r8, r3
??? .................................................
??? .................................................
我們可以發現在這個片斷中有太多的ldr(load, read from memory)和
str(store, wirte to memory),而且過多的load和str還影響了cpu和memory之間的cache的效
率,形成cache抖動。當發生cache miss時,cahce控制器花了大力氣把內容從memory搬到
cache,但是沒怎么用這個entry馬上又被替換掉。如果運氣不好,cache就一直這樣"抖動"。
在解碼過程中,各個模塊都各自為戰,都各自去占比較大的memory帶寬
如何減少這種無用的行為呢?必須讓關鍵代碼適應硬件體系結構,把數據流相關的代碼耦合
在一起。很多代碼通過模塊化得到了優秀的可讀性和可擴展性。魚與熊掌不可兼得,耦合在
一起的代碼會顯得比較晦澀難懂。ffmpeg/mplayer在這方面作了一個比較好的trade-off。
1、2、3的知識摘自網上,要比較好的理解以上內容需要一些視頻編、解碼的知識。?
BTW:http://blog.csdn.net/weixianlin/archive/2008/05/01/2358035.aspx
1. 在嵌入式系統中實現MPEG4的視頻解碼
有兩種方法可行
(1)采用ffmpeg(mplayer 的核心就是采用ffmpeg),然后對ffmpeg mp4解碼優化
1).對IDCT匯編化,并優化VLD的實現?? ->inline&匯編化
2).根據ARM9 cache&cache line的大小做MB的分組,使得每次可以同時處理多個MB
? 即對多個MB在一個循環內做VLD--->IDCT-->MC--.......? ->耦合
3).優化關鍵代碼段的內存訪問(MC)??? ->inline&匯編化
4).不要使用FFmpeg內置的img_convert()做yuv2rgb轉換? ->inline&匯編化
5).對解碼庫做ARM指令集優化??? ->體系結構優化
? configured ffmpeg with cpu = ARMV4L would give you a better performance
? If you have IPP,you can enable it, you can obtain huge enhancement
? IPP=Intel? Integrated Performance Primitives intel高性能構件庫(only for xScale)
?
(2)用xvid來做,ffmpeg包含的解碼庫太多,如果你只做MPPEG4解碼,何必用這么復雜的庫.
btw,在嵌入式系統中最好用0.9.2版的xvid。因為1.1.0的版本包含了很多AS的特性,通常在
嵌入式系統中都不需要用,并且也不容易實現。要自己做編碼算法的話,不能總想依賴別人
,最好還是需要自己花功夫去實現和優化。因此我覺得從實際出發的話,XVID0.9.2版的比
1.1.0的好。實際上,通常在主頻400MHz的平臺上,要優化XVID的算法達到CIF實時解碼也還
是很容易的,最多就一個多月
2. 視頻解碼流程對解碼帶來的影響
視頻解碼優化一般代碼量大,而且源代碼往往是從其他地方獲取得到的,所以閱讀比較困難
,更別說優化了,最近在優化realVideo,有幾點心得:
1).閱讀代碼前必須先熟悉流程,抓住關鍵的點,比如視頻解碼不外乎熵解碼,反量化,反變
換,插值,重建,濾波,參考幀插入等。把握住這幾個點,可以將代碼很快分離出來。
2). 分析解碼流程,了解解碼需要的最小buffer是多大,各個buffer 的位寬多大。
3).根據已經知道的流程,跟蹤代碼buffer流向,是否存在多余的內存拷貝。想辦法將buffer
減少,經驗說明,減少buffer帶來的速度上的提升遠大于局部算法的優化。 ->耦合
4).觀察程序結構順序是否合理,不合理的程序結構會導致buffer增大。
這兩天研究視頻解碼順序,發現先插值后做反變換要比先做反變換再做插值效率要高許多,
原因是插值后的位寬是8bits,而往往反變換后是9bits,所以在重建之前要保存插值后的值
要比保存反變換后的值要省一半的空間,這樣在重建時訪問的內存就少很多了。據我了解,
大部分高效率的解碼器都是先插值再反變換,而且變換后馬上做重建,這樣既減少內存使用
,也避免內存訪問抖動太厲害,最終減少緩存不命中。 ->修改解碼流程 耦合
3. cache機制對解碼帶來的影響
先看?http://www.hongen.com/pc/diy/know/mantan/cache0.htm
寫透(直寫式)和寫回(回寫式)有著截然不同的操作,在不同的場合,不同的內存塊使用
不同的回寫策略(如果你的系統可以實現的話)要比使用一種策略要高效得多。具體一點,
對于反復存取的內存塊置成寫回,而把一次寫入而很長時間以后再使用的內存置為寫透,可
以大大提高cache的效率。
第一點很容易理解,第二點就需要琢磨一下了,由于寫透的操作是,當緩存有該地址的數據
時同時更新緩存和主存,當緩存沒有該地址數據直接寫主存,忽略緩存。當該地址的數據很
長時間后才被使用到,那么在使用的時候該數據肯定不在cache中(被替換了),所以不如直
接寫入主存來得直接;
相反,如果使用寫回操作,當 cache中有該地址數據,需要更新該數據,設置dirty位,很長
時間后再使用該數據或被替換的時候才將其刷進主存,這有占了茅坑不拉屎的嫌疑;而當
?cache沒有該地址數據時,情況更糟糕,首先需要將相應的主存數據(一個cache line)導
?入cache,再更新數據,設置dirty位,再等待被刷回內存,這種情況不僅占用了cache的空
?間,還多一次從主存中導入數據的過程,同樣占據總線,開銷很大。至于為什么要先從主存
?中導入數據,是因為cache往主存回寫數據時是按照一個cache line 單位來寫的,但被更新
?的數據可能沒有一個cache line這么多,所以為了保證數據一致性,必須先把數據導入
?cache,更新后再刷回來。
對于很多視頻解碼來說,幀寫入過程是一個一次性的動作,只有在下一次作為參考幀時才會
被使用到,所以幀緩沖內存可以設置為寫透操作,而下一次使用它的時候很可能是作為參考
幀來使用,而作為參考幀不需要反復的存取,只需一次讀操作就可以了,所以效率并不會因
為不經過cache而降低。實驗證明該方法可以使 mpeg4 sp解碼提高20-30%的效率。
相似的內容cache操作的小技巧還有prefetch操作,prefetch操作是將主存的數據導入cache
而期間cpu不需要等待,繼續下一條指令的執行,如果下一條指令也是總線的操作,那么就必
須等待prefetch完成以后再開始。所以,在使用該指令時,在prefetch指令后面插入盡可能
大于一次緩存不命中所需要的clock數對應的指令,那么prefetch與其后面的指令可以并行執
行,從而省去了等待的過程,相當于抵消緩存不命中的損失。當然,如果插入的指令太多而
cache太小,有可能prefetch的數據進入cache 后又被替換掉了,所以,這需要自己去評估。?
->cache優化
4. 總結
IDCT是視頻解碼中關鍵步驟中的第一步,目前一般采用快速算法來做,如chen-wang 算法,
c語言和匯編的效果差別還是比較大的。
對一個8x8的block做idct做變換,如???
??? for (i = 0; i < 8; i++)
???? ??? idct_row (block + 8 * i);
??? for (i = 0; i < 8; i++)
???? ??? idct_col (block + i);
把他匯編后,主要是可以減少存儲器帶寬,提高存儲效率,避免無謂的內存讀寫。
mplayer 在此方面做了很多努力,針對armv4(s3c2440屬于armv4l架構)的相關文件放在
dsputil_arm_s.S文件中。但遺憾的是,它里面有一條指令PLD,cache預取指令2440是不支持
的。PLD指令屬于enhanced DSP指令,在armv4E(E 既代表enhanced DSP)才被支持,因此在我
們orchid上跑的代碼必須注釋掉這條指令,否則編譯不過.再把話題轉回來,在IDCT之前,視
頻壓縮流通過VLD(variable lenght decode)變長解碼得到DCT數據。這部分工作一般是通過
查表來加速性能,所有的編碼表會預先存起來。而取視頻比特流的代碼通常是宏,通過宏的
擴展來達到和匯編同樣的效果。在IDCT后還有關鍵的運動補償和色彩空間轉換兩個步驟。對
運動補償的加速也是通過匯編化,其代碼也同樣放在dsputil_arm_s.S 有必要一提的是在這
部分,如果有SIMD指令將會極大的提高它的速度。
color space轉換是解碼輸出后的最重要的一步。在嵌入式系統中,一般都是采用rgb565既
16bit來表示一個像素的色彩。
一個8x8的block,它的yuv(420格式)表示如下,
??????? YYYYYYYY
??????? YYYYYYYY
??????? YYYYYYYY
??????? YYYYYYYY
??????? UUUUUUUU
??????? VVVVVVVV
注意它的值是8bit的,通過裝換方程計算,可以得到像素值。在實現中通常采用查表來加速
計算,對于每一個Y,U,V都有一個對應表。對于1個320x240的video,共76800像素。如果每
個像素在這個轉換中節省10個cycle,那save下來的cpu還是相當可觀的。
當色彩空間轉換完后,就是通過把這個picture copy到framebuffer的內存里,這里存在一大
片的copy時間。有兩方面可以注意,一是有人實現過把轉換后的內存直接往framebuffer送,
減少最后所需的copy過程,這個idea確實不錯,但是需要一些技巧去實現,二是copy這個過程
本省也是可以加速的,在armv5以上的體系結構里,cpu----cache---memory,其中cache和
memory的寬度是32位,但cpu和cache的bus width確是64位,用32位的成本實現了64位的存儲
器。如果這個能被使用,那么理論上,copy速度可以加倍。在PC機上,一般我們的應用程序會有
fastmemorycopy這個函數,它們是用simd等特殊指令來實現,在armv5上則是通過它的總
線寬度來加速在s3c2440上不可用:( 它是v4架構。
總的來說:
(1).算法級的優化基本用無可用,ffmpeg/mplayer已經實現的相當不錯,除非自己實現一個
新的decoder;
(2).在代碼級,主要是通過關鍵代碼的inline(宏,inline函數)和匯編來加速。這部分在
arm平臺還是有一些潛力可挖
(3).硬件級,在這一層,cpu的體系結構決定指令集、cache的形式和大小等。如指令集是否
有enhanced DSP指令、SIMD指令,cache是否可配置、cache line大小,這些都會影響代碼級
和算法級的優化
(4).系統層優化,之所以把它放在最后一層,是由于它建立在整個系統之上,只有對整個系
統包括硬件和軟件有深刻的理解才能做到。
縱觀優化,其實質是盡可能的去除冗余計算,最大化的利用系統硬件資源。
對于RISC架構的cpu來講,先天不足的就是需要比較大的存儲器帶寬(因為RISC的指令都是基
于寄存器的,必須把操作數都load到內存才能計算),cpu資源被過多的使用在內存的read和
write。
以下面代碼為例,它是解碼輸出后,把yuv空間裝換成rgb空間的一個片斷
000111c :???????
??? 111c:?????? e92d4ff0??????? stmdb?? sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
??? 1120:?????? e1a0a000??????? mov???? sl, r0
??? 1124:?????? e5900038??????? ldr???? r0, [r0, #56]
??? 1128:?????? e1a0c001??????? mov???? ip, r1
??? 112c:?????? e3500004??????? cmp???? r0, #4? ; 0x4
??? 1130:?????? e24dd034??????? sub???? sp, sp, #52???? ; 0x34
??? 1134:?????? e1a00002??????? mov???? r0, r2
??? 1138:?????? e1a01003??????? mov???? r1, r3
??? 113c:?????? 0a00055d??????? beq???? 157c
??? 1140:?????? e59d2058??????? ldr???? r2, [sp, #88]
??? 1144:?????? e3520000??????? cmp???? r2, #0? ; 0x0
??? 1148:?????? d1a00002??????? movle?? r0, r2
??? 114c:?????? da00055b??????? ble???? 1574
??? 1150:?????? e59d3060??????? ldr???? r3, [sp, #96]
??? 1154:?????? e58d1030??????? str???? r1, [sp, #48]
??? 1158:?????? e5933000??????? ldr???? r3, [r3]
??? 115c:?????? e59f2434??????? ldr???? r2, [pc, #1076] ; 1598 <.text+0x1598>
??? 1160:?????? e0213193??????? mla???? r1, r3, r1, r3
??? 1164:?????? e58d3018??????? str???? r3, [sp, #24]
??? 1168:?????? e59d305c??????? ldr???? r3, [sp, #92]
??? 116c:?????? e58d1000??????? str???? r1, [sp]
??? 1170:?????? e5933000??????? ldr???? r3, [r3]
??? 1174:?????? e79a1002??????? ldr???? r1, [sl, r2]
??? 1178:?????? e58d301c??????? str???? r3, [sp, #28]
??? 117c:?????? e5903008??????? ldr???? r3, [r0, #8]
??? 1158:?????? e5933000??????? ldr???? r3, [r3]
??? 115c:?????? e59f2434??????? ldr???? r2, [pc, #1076] ; 1598 <.text+0x1598>
??? 1160:?????? e0213193??????? mla???? r1, r3, r1, r3
??? 1164:?????? e58d3018??????? str???? r3, [sp, #24]
??? 1168:?????? e59d305c??????? ldr???? r3, [sp, #92]
??? 116c:?????? e58d1000??????? str???? r1, [sp]
??? 1170:?????? e5933000??????? ldr???? r3, [r3]
??? 1174:?????? e79a1002??????? ldr???? r1, [sl, r2]
??? 1178:?????? e58d301c??????? str???? r3, [sp, #28]
??? 117c:?????? e5903008??????? ldr???? r3, [r0, #8]
??? 1180:?????? e59c4008??????? ldr???? r4, [ip, #8]
??? 1184:?????? e590e000??????? ldr???? lr, [r0]
??? 1188:?????? e59c2000??????? ldr???? r2, [ip]
??? 118c:?????? e5900004??????? ldr???? r0, [r0, #4]
??? 1190:?????? e59cc004??????? ldr???? ip, [ip, #4]
??? 1194:?????? e58d3014??????? str???? r3, [sp, #20]
??? 1198:?????? e1a011c1??????? mov???? r1, r1, asr #3? ;h_size
??? 119c:?????? e3a03000??????? mov???? r3, #0? ; 0x0
??? 11a0:?????? e58d4010??????? str???? r4, [sp, #16]
??? 11a4:?????? e58d2004??????? str???? r2, [sp, #4]
??? 11a8:?????? e58de020??????? str???? lr, [sp, #32]
??? 11ac:?????? e58d000c??????? str???? r0, [sp, #12]
??? 11b0:?????? e58dc008??????? str???? ip, [sp, #8]
??? 11b4:?????? e58d1028??????? str???? r1, [sp, #40]
??? 11b8:?????? e58d3024??????? str???? r3, [sp, #36]
??? 11bc:?????? e1a08003??????? mov???? r8, r3
??? .................................................
??? .................................................
我們可以發現在這個片斷中有太多的ldr(load, read from memory)和
str(store, wirte to memory),而且過多的load和str還影響了cpu和memory之間的cache的效
率,形成cache抖動。當發生cache miss時,cahce控制器花了大力氣把內容從memory搬到
cache,但是沒怎么用這個entry馬上又被替換掉。如果運氣不好,cache就一直這樣"抖動"。
在解碼過程中,各個模塊都各自為戰,都各自去占比較大的memory帶寬
如何減少這種無用的行為呢?必須讓關鍵代碼適應硬件體系結構,把數據流相關的代碼耦合
在一起。很多代碼通過模塊化得到了優秀的可讀性和可擴展性。魚與熊掌不可兼得,耦合在
一起的代碼會顯得比較晦澀難懂。ffmpeg/mplayer在這方面作了一個比較好的trade-off。
1、2、3的知識摘自網上,要比較好的理解以上內容需要一些視頻編、解碼的知識。?
BTW:http://blog.csdn.net/weixianlin/archive/2008/05/01/2358035.aspx