ffmpeg -s:v 352x288 -r 25 -i foreman_cif.yuv -vf scale=1280:720 -c:v rawvideo -pix_fmt yuv420p foreman_cif_720p.yuv
也可用於 downscale.
2015年9月29日 星期二
2015年9月22日 星期二
利用 FFMPEG 比較兩個 yuv file 的 PSNR 與 SSIM
1. 在 FFmpeg 資料夾下 make fate
2. 到 tests 資料夾裡找 tiny_psnr 與 tiny_ssim
3. tiny_psnr <file1> <file2>
2. 到 tests 資料夾裡找 tiny_psnr 與 tiny_ssim
3. tiny_psnr <file1> <file2>
2015年3月4日 星期三
FFmpeg transcode 指令
FFMPEG
// List available formats for ffmpeg
ffmpeg -pix_fmts
ffmpeg -pix_fmts
// Convert raw rgb565 image to png
ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 1024x768 -i freescale_1024x768.raw -f image2 -vcodec png screen.png
ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 1024x768 -i freescale_1024x768.raw -f image2 -vcodec png screen.png
// Convert png to raw rgb565
ffmpeg -vcodec png -i image.png -vcodec rawvideo -f rawvideo -pix_fmt rgb565 image.raw
ffmpeg -vcodec png -i image.png -vcodec rawvideo -f rawvideo -pix_fmt rgb565 image.raw
// Convert a 720x480 NV12 (YUV 420 semi-planar) image to png
ffmpeg -s 720x480 -pix_fmt nv12 -i image-nv12.yuv -f image2 -pix_fmt rgb24 image-png.png
ffmpeg -s 720x480 -pix_fmt nv12 -i image-nv12.yuv -f image2 -pix_fmt rgb24 image-png.png
// Convert a 640x480 uyvy422 image to png
ffmpeg -s 640x480 -pix_fmt uyvy422 -i image-uyvy422.yuv -f image2 -pix_fmt rgb24 image-uyvy422.png
//mux 264 to avi
ffmpeg -f h264 -i <filename>.264 -vcodec copy <filename>.avi2014年3月11日 星期二
Git 常用指令
1. git status
可以看到目前 Git 的狀態
2. git add <filename>
將檔案 filename 加入 staged
3. .gitignore 檔案讓你避免加入一些類型的檔案。格式大致上如下
# 註解,會被忽略。 # 不要追蹤檔名為 .a 結尾的檔案 *.a # 但是要追蹤 lib.a,即使上方已指定忽略所有的 .a 檔案 !lib.a # 只忽略根目錄下的 TODO 檔案。 不包含子目錄下的 TODO /TODO # 忽略build/目錄下所有檔案 build/ # 忽略doc/notes.txt但不包含doc/server/arch.txt doc/*.txt # ignore all .txt files in the doc/ directory doc/**/*.txt
4. git diff
命令比對目前工作目錄及暫存區域後告訴讀者哪些變更尚未被暫存。
5. git diff --staged
這命令比對暫存區域及最後一個提交。
6. git commit -m "message" 或 git commit -m '可換行'
7. git rm
從已被追蹤檔案中移除並且提交
8. git log -p
列出每次的更新之間差別的內容
9. git log --stat
列出更新之間差別的內容的大綱
10. git commit --amend (會出現一個文書編輯器)
重新 commit ,例如想要修改上次 commit 或上次commit 漏掉了一些檔案沒 commit 可以用這個
11. git reset HEAD <filename>
將 filename 從 staged 中移除,取消暫存。
12. git checkout <PATH>
將 PATH 以下的檔案都 checkout。復原到最後一次 commit 的狀態。
13. git remote add [shortname] [url]
增加新的遠端儲存庫
14. git fetch [remote-name]
將所有本地端沒有的資料拉下來。僅僅將資料拉到本地端的儲存庫,但沒有合併,跟 git pull 不同。
15. git remote show [remote-name]
看資訊可以看到remote branch, 跟 local branck track 的情形
16.
17. git branch
看 branch, 加 -d [branch name] 可以刪除 branch
18. git checkout -b [branch_name]
直接開啟一個 branch_name 的分支並把 head 指向他。
19. git merge [branch_name]
將 branch_name 分支和到目前 head 指向的分支。
20. git checkout --track origin/serverfix 建立一個 "tracking branch" for remote branch " origin/serverfix "
21. git branch -vv 觀察local branch 跟 remote branch 的關係
22. git reflog
git reset [sha]
可以回復 git reset --hard
23. 查看 git repository 是從哪個地方 clone 的 url 位置
git config --get remote.origin.url
24. git rev-parse --verify HEAD
查看 HEAD 所指的 SHA-1 value
25. git push -u origin new_branch # 建立遠端 branch (將 new_branch 建立到遠端)
可以看到目前 Git 的狀態
2. git add <filename>
將檔案 filename 加入 staged
3. .gitignore 檔案讓你避免加入一些類型的檔案。格式大致上如下
# 註解,會被忽略。 # 不要追蹤檔名為 .a 結尾的檔案 *.a # 但是要追蹤 lib.a,即使上方已指定忽略所有的 .a 檔案 !lib.a # 只忽略根目錄下的 TODO 檔案。 不包含子目錄下的 TODO /TODO # 忽略build/目錄下所有檔案 build/ # 忽略doc/notes.txt但不包含doc/server/arch.txt doc/*.txt # ignore all .txt files in the doc/ directory doc/**/*.txt
4. git diff
命令比對目前工作目錄及暫存區域後告訴讀者哪些變更尚未被暫存。
5. git diff --staged
這命令比對暫存區域及最後一個提交。
6. git commit -m "message" 或 git commit -m '可換行'
7. git rm
從已被追蹤檔案中移除並且提交
8. git log -p
列出每次的更新之間差別的內容
9. git log --stat
列出更新之間差別的內容的大綱
10. git commit --amend (會出現一個文書編輯器)
重新 commit ,例如想要修改上次 commit 或上次commit 漏掉了一些檔案沒 commit 可以用這個
11. git reset HEAD <filename>
將 filename 從 staged 中移除,取消暫存。
12. git checkout <PATH>
將 PATH 以下的檔案都 checkout。復原到最後一次 commit 的狀態。
13. git remote add [shortname] [url]
增加新的遠端儲存庫
14. git fetch [remote-name]
將所有本地端沒有的資料拉下來。僅僅將資料拉到本地端的儲存庫,但沒有合併,跟 git pull 不同。
15. git remote show [remote-name]
看資訊可以看到remote branch, 跟 local branck track 的情形
16.
git reset --hard 某個版本的 hash 編號 # 整個 Repository 恢復到某個版本的狀態17. git branch
看 branch, 加 -d [branch name] 可以刪除 branch
18. git checkout -b [branch_name]
直接開啟一個 branch_name 的分支並把 head 指向他。
19. git merge [branch_name]
將 branch_name 分支和到目前 head 指向的分支。
20. git checkout --track origin/serverfix 建立一個 "tracking branch" for remote branch " origin/serverfix "
21. git branch -vv 觀察local branch 跟 remote branch 的關係
22. git reflog
git reset [sha]
可以回復 git reset --hard
23. 查看 git repository 是從哪個地方 clone 的 url 位置
git config --get remote.origin.url
24. git rev-parse --verify HEAD
查看 HEAD 所指的 SHA-1 value
25. git push -u origin new_branch # 建立遠端 branch (將 new_branch 建立到遠端)
2014年2月9日 星期日
int& a = b 的解釋
以下是在 cplusplus 網頁上看到的
int a = b is setting a's VALUE to b's VALUE
int* a = &b is setting a's VALUE to the ADDRESS of b
int& a = b is setting a's ADDRESS to b's ADDRESS (a is a reference to b)
上面話的用我自己的理解來解釋如下
int& a = b 的用法就是說,將 a 的 address 設定為 b 的 address,換居話說 a 幾乎就跟 b 一模一樣。
用 printf 來表示應該如下
================================
第一個 case int a=b
int b = 5;
int a = b
pintf ( a, b, &a, &b ) 可能會有如下結果
(5, 5, 0xdfe0, 0xad06) 兩個 address 不一樣
================================
================================
第二個 case int* a=b
int b = 5;
int *a = b
pintf ( a, b, &a, &b ) 可能會有如下結果
(0xad06, 5, 0xdfe0, 0xad06) a 的值就是 b 的 address
================================
================================
第三個 case int& a=b
int b = 5;
int &a = b
pintf ( a, b, &a, &b ) 可能會有如下結果
a = 5, b = 5, &a = 0x2a1ae39c, &b = 0x2a1ae39c
a 就是 b
================================
第三個 case 我有真的打印來看,不會有問題。
int a = b is setting a's VALUE to b's VALUE
int* a = &b is setting a's VALUE to the ADDRESS of b
int& a = b is setting a's ADDRESS to b's ADDRESS (a is a reference to b)
上面話的用我自己的理解來解釋如下
int& a = b 的用法就是說,將 a 的 address 設定為 b 的 address,換居話說 a 幾乎就跟 b 一模一樣。
用 printf 來表示應該如下
================================
第一個 case int a=b
int b = 5;
int a = b
pintf ( a, b, &a, &b ) 可能會有如下結果
(5, 5, 0xdfe0, 0xad06) 兩個 address 不一樣
================================
================================
第二個 case int* a=b
int b = 5;
int *a = b
pintf ( a, b, &a, &b ) 可能會有如下結果
(0xad06, 5, 0xdfe0, 0xad06) a 的值就是 b 的 address
================================
================================
第三個 case int& a=b
int b = 5;
int &a = b
pintf ( a, b, &a, &b ) 可能會有如下結果
a = 5, b = 5, &a = 0x2a1ae39c, &b = 0x2a1ae39c
a 就是 b
================================
第三個 case 我有真的打印來看,不會有問題。
Android 4.3 surfaceflinger 中的 handleMessageTransaction
在我工作的平台上,HDMI output ,每次 vsync 發生時 surfaceflinger 收到的 message 是 MessageQueue::INVALIDATE。然後surfaceflinger 會執行下面 function ,
handleMessageTransaction();
handleMessageInvalidate();
signalRefresh();
這篇主要先分析 handleMessageTransaction()。而這個 function 全文在 4.3 中如下
void SurfaceFlinger::handleMessageTransaction() {
uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
if (transactionFlags) {
handleTransaction(transactionFlags);
}
}
他會先透過 peekTransactionFlags(eTransactionMask),來窺視 mTransactionFlags 是否非零,如果是才會進入 handleTransaction(transactionFlags)。mTransactionFlags 是 surfaceflinger 中的一個 member ,當有某個 surface 狀態有改變或createSurface、 removeSurface、addLayer 等等的行為發生時都會透過 SurfaceFlinger::setTransactionFlags() 設定這個 flag 。目前有三個 bit 可被設置,分別如下
enum {
eTransactionNeeded = 0x01, (二進位表示0001)
eTraversalNeeded = 0x02, (二進位表示0010)
eDisplayTransactionNeeded = 0x04, (二進位表示0100)
eTransactionMask = 0x07 (二進位表示0111)
};
其中個別代表什麼還不是很清楚,在 surfaceflinger 搜尋 setTransactionFlags 看到 eTransactionNeeded 會在 createLayer、removeLaye 中被設置。eDisplayTransactionNeeded 則在 createDisplay() 跟 onHotplugReceived () 中被設置,。eTraversalNeeded 則是在 surfaceFlinger 裡面我搜尋不到,應該是由別的地方去設置,將來有看到再補。
========================================================================
回到 handleMessageTransaction 中,上面的任何一個情況有發生,才會呼叫 handleTransaction 。
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
// Here we're guaranteed that some transaction flags are set
// so we can call handleTransactionLocked() unconditionally.
// We call getTransactionFlags(), which will also clear the flags,
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
}
這個很短沒什麼特別需要解釋的,其中 invalidateHwcGeometry 這個 function 只是執行 mHwWorkListDirty = true,實際上做什麼目前還不清楚,之後有看到再補。
所以接下來就是進入 handleTransactionLocked()中。
========================================================================
handleTransactionLocked 比較長,主要就是去檢視上面提到的 mTransactionFlags 來執行對應的工作。還是照著順序來吧。
首先,檢查 eTraversalNeeded 是否有被拉起來,有的話,顧名思義 traversal 所有 layer。
if (transactionFlags & eTraversalNeeded) {
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
}
}
layer->getTransactionFlags(eTransactionNeeded) 會檢查 layer 類別中的成員 mTransactionFlags 的 eTransactionNeeded 是否被設置。注意這裡的 mTransactionFlags 只給每個 layer 自己用 ,surfaceflinger 中也有一個名稱一樣的(也就是上面提的),不要搞混了。如果目前掃到的 layer 的 eTransactionNeeded 有被設置,就執行
layer->doTransaction。
接著分析 Layer 中的 doTransaction 在做什麼。首先
const Layer::State& front(drawingState());
const Layer::State& temp(currentState());
const bool sizeChanged = (temp.requested.w != front.requested.w) ||
(temp.requested.h != front.requested.h);
if (sizeChanged) {
// record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
mSurfaceFlingerConsumer->setDefaultBufferSize(
temp.requested.w, temp.requested.h);
}
drawingState 會回傳 Layer 中的 mDrawingState ,代表的是 " 上一次 drawing " 的 layer 狀態;而 currentState 會回傳 mCurrentState,代表此 layer 目前狀態。得到狀態後,首先檢查是否發生尺寸上的變化(sizeChanged),如果有發生改變就執行 mSurfaceFlingerConsumer->setDefaultBufferSize(temp.requested.w, temp.requested.h); 這裡實際運作情況待補,現在就把他理解成會根據不同的尺寸來設定 mDefaultWidth 跟 mDefaultHeight,之後會根據這兩個值來設定 Buffer 大小。
接著
if (!isFixedSize()) {
const bool resizePending = (temp.requested.w != temp.active.w) ||
(temp.requested.h != temp.active.h);
if (resizePending) {
// don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// the drawing state will be updated only once we receive a buffer
// with the correct size.
//
// in particular, we want to make sure the clip (which is part
// of the geometry state) is latched together with the size but is
// latched immediately when no resizing is involved.
flags |= eDontUpdateGeometryState;
}
}
上面有三個 if 判斷式,第一個就是如果 eDontUpdateGeometryState 被拉起來,那就不會把 requested assign 給 active,如果這邊猜測沒有問題的話,接下來的判斷式
if (front.active != temp.active)
會檢查上一次跟這一次的 active 一不一樣,不一樣的話會拉 eVisibleRegion 表示 visible region 有改變。
第三個判斷式是判斷 drawing 跟 current 的 sequence 值是否一樣,mCurrentState.sequence 在很多 Layer 的改變的操作被呼叫時(例如:setLayer、setSize 等)就會被累加一 。如果不一樣的話也拉 eVisibleRegion,然後將 contentDirty 設為 true ,接著會修改 mNeedsFiltering 值。
雖然從程式邏輯上很容易可以理解這些步驟,但是這些東西到底是要做什麼的從這邊不太容易看出來。尤其是 eDontUpdateGeometryState 這個東西該怎麼理解 。之後理解了再補上。
最後會呼叫 commitTransaction(),這個 function 內容如下,很簡單。
void Layer::commitTransaction() {
mDrawingState = mCurrentState;
}
最後 return flag,然後我們離開 doTrasaction 啦! 程式回到 handleTransactionLocked,doTrasaction 之後馬上有人檢查 return 的值
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
如果有任何一個 Layer 有變動,就會把 mVisibleRegionsDirty 設為 true。
========================================================================
接著再繼續 handleTransactionLocked,第二個要確認的 flag 是 eDisplayTransactionNeeded
從上面可以稍微了解到 eDisplayTransactionNeeded 是在 createDisplay 或 onHotplugReceived 發生時會被拉起來。所以這邊我可以稍微猜想一下他會做什麼。基本上他應該會‧‧‧‧,痾‧‧‧,算了!看 code 吧。
以 createDisplay 為例,createDisplay 中會呼叫
mCurrentState.displays.add(token, info);
加入一個 DisplayDeviceState 進 display 這個 DefaultKeyedVector 中。 DefaultKeyedVector 宣告如下
class DefaultKeyedVector : public KeyedVector<KEY, VALUE>
●
●
●
}
}
而裡面的工作主要是歷遍整個 mDrawingState.displays 中的所有物件,然後利用
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
來判斷是否存在於 mCurrentState.displays 中, j < 0 的話表示沒有,代表在新的 state 中已被移除。如果已被移除,判斷如果不是 DISPLAY_PRIMARY ( 代表手機螢幕) 則先將 defaultDisplay makeCurrent (此處跟 EGL 相關,簡單講就是將 display 設回手機螢幕),接著在移除這個 display 。
如果 j > 0 表示他還沒被移除,就檢查一下他的狀態是否有被改變,有的話再做對應的動作 (setLayerStack、setProjection 等等)。
上面是遍歷整個 mDrawingState.displays 來判斷是否有物件被移除,接著反過來歷遍整個 mCurrentState.displays 看是否有物件被新加進來,然後作對應的處理 (先略)。
========================================================================
在 4.2 的 MessageQueue::INVALIDATE 的訊息處理還有兩個 function 被執行
handleMessageInvalidate();
signalRefresh();
signalRefresh 看似會發 MessageQueue::REFRESH ,所以等於還是會執行 handleMessageRefresh
裡面還有好幾個 function 。
handleMessageTransaction();
handleMessageInvalidate();
signalRefresh();
這篇主要先分析 handleMessageTransaction()。而這個 function 全文在 4.3 中如下
void SurfaceFlinger::handleMessageTransaction() {
uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
if (transactionFlags) {
handleTransaction(transactionFlags);
}
}
他會先透過 peekTransactionFlags(eTransactionMask),來窺視 mTransactionFlags 是否非零,如果是才會進入 handleTransaction(transactionFlags)。mTransactionFlags 是 surfaceflinger 中的一個 member ,當有某個 surface 狀態有改變或createSurface、 removeSurface、addLayer 等等的行為發生時都會透過 SurfaceFlinger::setTransactionFlags() 設定這個 flag 。目前有三個 bit 可被設置,分別如下
enum {
eTransactionNeeded = 0x01, (二進位表示0001)
eTraversalNeeded = 0x02, (二進位表示0010)
eDisplayTransactionNeeded = 0x04, (二進位表示0100)
eTransactionMask = 0x07 (二進位表示0111)
};
其中個別代表什麼還不是很清楚,在 surfaceflinger 搜尋 setTransactionFlags 看到 eTransactionNeeded 會在 createLayer、removeLaye 中被設置。eDisplayTransactionNeeded 則在 createDisplay() 跟 onHotplugReceived () 中被設置,。eTraversalNeeded 則是在 surfaceFlinger 裡面我搜尋不到,應該是由別的地方去設置,將來有看到再補。
========================================================================
回到 handleMessageTransaction 中,上面的任何一個情況有發生,才會呼叫 handleTransaction 。
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
// Here we're guaranteed that some transaction flags are set
// so we can call handleTransactionLocked() unconditionally.
// We call getTransactionFlags(), which will also clear the flags,
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
}
這個很短沒什麼特別需要解釋的,其中 invalidateHwcGeometry 這個 function 只是執行 mHwWorkListDirty = true,實際上做什麼目前還不清楚,之後有看到再補。
所以接下來就是進入 handleTransactionLocked()中。
========================================================================
handleTransactionLocked 比較長,主要就是去檢視上面提到的 mTransactionFlags 來執行對應的工作。還是照著順序來吧。
首先,檢查 eTraversalNeeded 是否有被拉起來,有的話,顧名思義 traversal 所有 layer。
if (transactionFlags & eTraversalNeeded) {
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
}
}
layer->getTransactionFlags(eTransactionNeeded) 會檢查 layer 類別中的成員 mTransactionFlags 的 eTransactionNeeded 是否被設置。注意這裡的 mTransactionFlags 只給每個 layer 自己用 ,surfaceflinger 中也有一個名稱一樣的(也就是上面提的),不要搞混了。如果目前掃到的 layer 的 eTransactionNeeded 有被設置,就執行
layer->doTransaction。
接著分析 Layer 中的 doTransaction 在做什麼。首先
const Layer::State& front(drawingState());
const Layer::State& temp(currentState());
const bool sizeChanged = (temp.requested.w != front.requested.w) ||
(temp.requested.h != front.requested.h);
if (sizeChanged) {
// record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
mSurfaceFlingerConsumer->setDefaultBufferSize(
temp.requested.w, temp.requested.h);
}
drawingState 會回傳 Layer 中的 mDrawingState ,代表的是 " 上一次 drawing " 的 layer 狀態;而 currentState 會回傳 mCurrentState,代表此 layer 目前狀態。得到狀態後,首先檢查是否發生尺寸上的變化(sizeChanged),如果有發生改變就執行 mSurfaceFlingerConsumer->setDefaultBufferSize(temp.requested.w, temp.requested.h); 這裡實際運作情況待補,現在就把他理解成會根據不同的尺寸來設定 mDefaultWidth 跟 mDefaultHeight,之後會根據這兩個值來設定 Buffer 大小。
接著
if (!isFixedSize()) {
const bool resizePending = (temp.requested.w != temp.active.w) ||
(temp.requested.h != temp.active.h);
if (resizePending) {
// don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// the drawing state will be updated only once we receive a buffer
// with the correct size.
//
// in particular, we want to make sure the clip (which is part
// of the geometry state) is latched together with the size but is
// latched immediately when no resizing is involved.
flags |= eDontUpdateGeometryState;
}
}
// always set active to requested, unless we're asked not to
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
Layer::State& editTemp(currentState());
editTemp.active = temp.requested;
}
調用 isFixedSize 來判斷 mCurrentScalingMode 是否為 FixedSize mode,如果不是 fixed size 的則進去判斷 current state 中的 request 跟 active 的 width 跟 height 是否相同,不相同的話,就把 eDontUpdateGeometryState 這個 flag 拉起來。然後進入下列的幾個判斷式
// always set active to requested, unless we're asked not to
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
Layer::State& editTemp(currentState());
editTemp.active = temp.requested;
}
if (front.active != temp.active) {
// invalidate and recompute the visible regions if needed
flags |= Layer::eVisibleRegion;
}
if (temp.sequence != front.sequence) {
// invalidate and recompute the visible regions if needed
flags |= eVisibleRegion;
this->contentDirty = true;
// we may use linear filtering, if the matrix scales us
const uint8_t type = temp.transform.getType();
mNeedsFiltering = (!temp.transform.preserveRects() ||
(type >= Transform::SCALE));
}
上面有三個 if 判斷式,第一個就是如果 eDontUpdateGeometryState 被拉起來,那就不會把 requested assign 給 active,如果這邊猜測沒有問題的話,接下來的判斷式
if (front.active != temp.active)
會檢查上一次跟這一次的 active 一不一樣,不一樣的話會拉 eVisibleRegion 表示 visible region 有改變。
第三個判斷式是判斷 drawing 跟 current 的 sequence 值是否一樣,mCurrentState.sequence 在很多 Layer 的改變的操作被呼叫時(例如:setLayer、setSize 等)就會被累加一 。如果不一樣的話也拉 eVisibleRegion,然後將 contentDirty 設為 true ,接著會修改 mNeedsFiltering 值。
雖然從程式邏輯上很容易可以理解這些步驟,但是這些東西到底是要做什麼的從這邊不太容易看出來。尤其是 eDontUpdateGeometryState 這個東西該怎麼理解 。之後理解了再補上。
最後會呼叫 commitTransaction(),這個 function 內容如下,很簡單。
void Layer::commitTransaction() {
mDrawingState = mCurrentState;
}
最後 return flag,然後我們離開 doTrasaction 啦! 程式回到 handleTransactionLocked,doTrasaction 之後馬上有人檢查 return 的值
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
如果有任何一個 Layer 有變動,就會把 mVisibleRegionsDirty 設為 true。
========================================================================
接著再繼續 handleTransactionLocked,第二個要確認的 flag 是 eDisplayTransactionNeeded
從上面可以稍微了解到 eDisplayTransactionNeeded 是在 createDisplay 或 onHotplugReceived 發生時會被拉起來。所以這邊我可以稍微猜想一下他會做什麼。基本上他應該會‧‧‧‧,痾‧‧‧,算了!看 code 吧。
以 createDisplay 為例,createDisplay 中會呼叫
mCurrentState.displays.add(token, info);
加入一個 DisplayDeviceState 進 display 這個 DefaultKeyedVector 中。 DefaultKeyedVector 宣告如下
class DefaultKeyedVector : public KeyedVector<KEY, VALUE>
它繼承自 KeyedVector,可以透過 valueFor(const KEY& key)用 key 值找到對應的物件(value),或透過 isIdenticalTo(const KeyedVector& rhs) 比對兩個 KeyedVector 是否相同。
所以當 createDisplay 發生時,下面兩個 if 判斷式應該都會成立,所以這個 case 主要的工作就是 if (!curr.isIdenticalTo(draw)) 成立後裡面做的事。(這邊舉 createDisplay 只是要知道有那些時候會進入這個條件,後面的介紹跟這個 function 在沒關係。)
if (transactionFlags & eDisplayTransactionNeeded) {
// here we take advantage of Vector's copy-on-write semantics to
// improve performance by skipping the transaction entirely when
// know that the lists are identical
const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
if (!curr.isIdenticalTo(draw)) {
●
●
}
}
而裡面的工作主要是歷遍整個 mDrawingState.displays 中的所有物件,然後利用
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
來判斷是否存在於 mCurrentState.displays 中, j < 0 的話表示沒有,代表在新的 state 中已被移除。如果已被移除,判斷如果不是 DISPLAY_PRIMARY ( 代表手機螢幕) 則先將 defaultDisplay makeCurrent (此處跟 EGL 相關,簡單講就是將 display 設回手機螢幕),接著在移除這個 display 。
如果 j > 0 表示他還沒被移除,就檢查一下他的狀態是否有被改變,有的話再做對應的動作 (setLayerStack、setProjection 等等)。
上面是遍歷整個 mDrawingState.displays 來判斷是否有物件被移除,接著反過來歷遍整個 mCurrentState.displays 看是否有物件被新加進來,然後作對應的處理 (先略)。
========================================================================
在 4.2 的 MessageQueue::INVALIDATE 的訊息處理還有兩個 function 被執行
handleMessageInvalidate();
signalRefresh();
signalRefresh 看似會發 MessageQueue::REFRESH ,所以等於還是會執行 handleMessageRefresh
裡面還有好幾個 function 。
2014年1月2日 星期四
Android 4.3 sp<> 與 wp<> 、Smart Pointer、紀錄
Google Android Smart Pointer 會有很多相關的知識可以參考,這邊只列一些簡單的用法跟注意事項。
普通指標宣告如下,
MyClass *p;
改成用 Smart pointer 如下,
sp<MyClass> p;
p 是指標 (注意不要寫成 sp<MyClass> *p; ), <XXX> 的用法是 C++ 的 template 。然後就可以用這個指標指向一個 new 出來的 object。
p = new MyClass();
而且不需要去 delete 。在 Android 中,上面的等號是經過重載的,表面上意義跟一般等號一樣,實際上的行為除了設定 sp 中的 private 成員 m_ptr,還會執行"目前物件的 incStrong" 跟"原本這個指標指向的物件的 decStrong" 等,後面會再詳述 。
sp 是一個 object,常常會把要指定給 p 的 object 直接傳給 sp 的建構式,下面列出 4.3 版的 sp 建構式。
1. sp(T* other);
2. sp(const sp<T>& other);
3. template<typename U> sp(U* other);
4. template<typename U> sp(const sp<U>& other);
(1)是最常見的,舉例如下
sp<Client> client (new Client());
會直接把 new 出來的 object assigne 到 m_ptr,m_ptr是 sp 這個 class 的 private 成員,型別是
T* m_ptr;
用來指向實際物件的位置。當你用 smart pointer 要存取Client的成員的時候,例如
client->initCheck();
實際上 -> 運算子會 return m_ptr。所以是透過 m_ptr 來執行 initCheck() 的,
m_ptr->initCheck();
接著看有沒有其他建構方式的例子。
(2) sp(const sp<T>& other); 就是把另一個在其他地方 new 好的 sp 指標,指定給目前的 sp 指標,例如
sp<const DisplayDevice> hw(getDefaultDisplayDevice());
getDefaultDisplayDevice 裡面太複雜就不分析了,有機會看能不能找到其他例子把他替換掉,整體來講這個的觀念如下
sp<Myclass> p1( new MyClass() );
sp<Myclass> p2 (p1)
補充一下,sp(const sp<T>& other) 中的 sp<T>& ,表示調用 sp 建構式時,參數 other 是以 call by reference 方式傳遞的。
(3)跟(4) 分別對應到上面兩種方式,差別在於參數中的型別是不一樣的,template<typename U>,建構時會把 U 轉型成 T,通常 U 跟 T 應該會有繼承關係。
====================================================================
那 sp 是如何做到自動釋放記憶體呢? 答案在 RefBase 這個 object 中,每當 object 透過 sp 來引用的時候,都會執行 incStrong() 這個 RefBase 的成員,incStrong會把引用計數 mStrong 加 1,然後如果是第一次被引用,還會順便執行 onFirstRef(),
反之,當物件不在被引用時,例如 client = NULL時,會執行 decStrong 來把引用計數 mStrong 減 1,如果 mStrong 變為 0,就會執行 delete 把物件存記憶體釋放,藉此達到自動釋放的功能。
所以,注意啦!所有要用到 smart pointer 的類別,都必須繼承自 RefBase 或 LightRefBase。例如上例的Client,慢慢追你會追到他就是繼承自 RefBase 。
class Client : public BnSurfaceComposerClient
class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient>
注:Client 這個類別定義在\frameworks\native\services\surfaceflinger\Client.h
普通指標宣告如下,
MyClass *p;
改成用 Smart pointer 如下,
sp<MyClass> p;
p 是指標 (注意不要寫成 sp<MyClass> *p; ), <XXX> 的用法是 C++ 的 template 。然後就可以用這個指標指向一個 new 出來的 object。
p = new MyClass();
而且不需要去 delete 。在 Android 中,上面的等號是經過重載的,表面上意義跟一般等號一樣,實際上的行為除了設定 sp 中的 private 成員 m_ptr,還會執行"目前物件的 incStrong" 跟"原本這個指標指向的物件的 decStrong" 等,後面會再詳述 。
sp 是一個 object,常常會把要指定給 p 的 object 直接傳給 sp 的建構式,下面列出 4.3 版的 sp 建構式。
1. sp(T* other);
2. sp(const sp<T>& other);
3. template<typename U> sp(U* other);
4. template<typename U> sp(const sp<U>& other);
(1)是最常見的,舉例如下
sp<Client> client (new Client());
會直接把 new 出來的 object assigne 到 m_ptr,m_ptr是 sp 這個 class 的 private 成員,型別是
T* m_ptr;
用來指向實際物件的位置。當你用 smart pointer 要存取Client的成員的時候,例如
client->initCheck();
實際上 -> 運算子會 return m_ptr。所以是透過 m_ptr 來執行 initCheck() 的,
m_ptr->initCheck();
接著看有沒有其他建構方式的例子。
(2) sp(const sp<T>& other); 就是把另一個在其他地方 new 好的 sp 指標,指定給目前的 sp 指標,例如
sp<const DisplayDevice> hw(getDefaultDisplayDevice());
getDefaultDisplayDevice 裡面太複雜就不分析了,有機會看能不能找到其他例子把他替換掉,整體來講這個的觀念如下
sp<Myclass> p1( new MyClass() );
sp<Myclass> p2 (p1)
補充一下,sp(const sp<T>& other) 中的 sp<T>& ,表示調用 sp 建構式時,參數 other 是以 call by reference 方式傳遞的。
(3)跟(4) 分別對應到上面兩種方式,差別在於參數中的型別是不一樣的,template<typename U>,建構時會把 U 轉型成 T,通常 U 跟 T 應該會有繼承關係。
====================================================================
那 sp 是如何做到自動釋放記憶體呢? 答案在 RefBase 這個 object 中,每當 object 透過 sp 來引用的時候,都會執行 incStrong() 這個 RefBase 的成員,incStrong會把引用計數 mStrong 加 1,然後如果是第一次被引用,還會順便執行 onFirstRef(),
反之,當物件不在被引用時,例如 client = NULL時,會執行 decStrong 來把引用計數 mStrong 減 1,如果 mStrong 變為 0,就會執行 delete 把物件存記憶體釋放,藉此達到自動釋放的功能。
所以,注意啦!所有要用到 smart pointer 的類別,都必須繼承自 RefBase 或 LightRefBase。例如上例的Client,慢慢追你會追到他就是繼承自 RefBase 。
class Client : public BnSurfaceComposerClient
class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient>
class BnInterface : public INTERFACE, public BBinder
class ISurfaceComposerClient : public IInterface
class IInterface : public virtual RefBase
如上,包很厚。
注:Client 這個類別定義在\frameworks\native\services\surfaceflinger\Client.h
========================================================================
wp 的觀念基本上跟 sp 一樣,但要用 wp 的 object 一定得是繼承自 RefBase。
而 wp 的引用計數是 mWeak,當 wp 被建構或解構時分別會呼叫 incWeak() 跟 decWeak() 來改變引用計數。另外 sp 在 incStrong (decStrong) 執行時也會呼叫 incWeak (decWeak)。這個部分在觀念上有點像是 sp 是 wp 的 superset。但也不能完全這樣講,因為有些 wp 的運算 sp 也不能直接使用的樣子。
wp 不能直接存取所指物件的成員,如果要存取所指物件的成員,需要透過 promote() 將 wp 升級為 sp。例如:
sp<A> p1 ;
wp<A> p2 ( new A());
p1 = p2.promote();
A->member();
wp 只重載比較運算子 (==、 != 、 >=、 <= 等),所以只能透過 wp 來比較兩個物件 (上段講的sp 不能說完全是 wp 的 superset 就是這裡,我從程式看起來似乎 sp 無法直接使用這些比較運算)。
========================================================================
RefBase 提供 extendObjectLifetime(int32_t mode); 讓使用者改變物件的生命週期,決定何時要 delete 物件, 參數 mode 的值可以如下定義:
enum {
OBJECT_LIFETIME_STRONG = 0x0000, // mStrong 為 0 時 delete 物件
OBJECT_LIFETIME_WEAK = 0x0001, // mWeak 為 0 時 delete 物件
OBJECT_LIFETIME_MASK = 0x0001 //
};
所以當你設定為 OBJECT_LIFETIME_WEAK 時,表示就算只有 wp ,物件還是不會被刪除。會保留到當連 wp 都沒有的時候才會 delete 掉物件。至於這個使用的時機跟目的該怎麼解釋,目前我還不甚了解,改天有看到例子再補。
而 wp 的引用計數是 mWeak,當 wp 被建構或解構時分別會呼叫 incWeak() 跟 decWeak() 來改變引用計數。另外 sp 在 incStrong (decStrong) 執行時也會呼叫 incWeak (decWeak)。這個部分在觀念上有點像是 sp 是 wp 的 superset。但也不能完全這樣講,因為有些 wp 的運算 sp 也不能直接使用的樣子。
wp 不能直接存取所指物件的成員,如果要存取所指物件的成員,需要透過 promote() 將 wp 升級為 sp。例如:
sp<A> p1 ;
wp<A> p2 ( new A());
p1 = p2.promote();
A->member();
wp 只重載比較運算子 (==、 != 、 >=、 <= 等),所以只能透過 wp 來比較兩個物件 (上段講的sp 不能說完全是 wp 的 superset 就是這裡,我從程式看起來似乎 sp 無法直接使用這些比較運算)。
========================================================================
RefBase 提供 extendObjectLifetime(int32_t mode); 讓使用者改變物件的生命週期,決定何時要 delete 物件, 參數 mode 的值可以如下定義:
enum {
OBJECT_LIFETIME_STRONG = 0x0000, // mStrong 為 0 時 delete 物件
OBJECT_LIFETIME_WEAK = 0x0001, // mWeak 為 0 時 delete 物件
OBJECT_LIFETIME_MASK = 0x0001 //
};
所以當你設定為 OBJECT_LIFETIME_WEAK 時,表示就算只有 wp ,物件還是不會被刪除。會保留到當連 wp 都沒有的時候才會 delete 掉物件。至於這個使用的時機跟目的該怎麼解釋,目前我還不甚了解,改天有看到例子再補。
訂閱:
文章 (Atom)