Android 的 AV sync

我們播放多媒體檔案的時候, 很容易注意到 “沒有對嘴" 的情況, 這就是所謂的 lips sync (= synchronization) 或是 Audio-Video sync 的問題.

螃蟹公司怎麼做 AV sync 我不能告訴大家. 但是 Android 的世界裡就沒有太多秘密, 它又是如何做 AV sync 的呢? 

首先它不喜歡用傳統的 PTS (Presentation Time Stamp) 做單位, 而是採用 µs (微秒). 1 秒等於 90,000 PTS, 也等於 1,000,000 微秒. 即使在程式裡面還是難免用到 PTS 的概念, 不過 Android 的上層已經把它轉為時間的單位了.

在 Android 還使用 OpenCore 當播放器的時代, audio 和 video 分別和系統時間 (NPT = normal play time) 校正 [ref 1]. 由於媒體錄製的機器所使用的時鐘 (clock) 和播放器的時鐘會有一定的差異, 所以校正是必須的. 但是往往這個差異相當地小 (若干 ppm  – 百萬分之一的等級), 看完一部 MV 大概發現不了, 或許要看一部電影才會發現.

到了 StageFright 的時代, 計算好像有變複雜一點? 我只參考了兩篇網路文章 [ref 2, 3], 瞭解可能不夠全面. 不過以我對 AV sync 的瞭解, 看起來還是頗能自圓其說. 以下是我歸納的 rules.

1. 首先我們要知道依據播放器的時鐘, 我們已經播出了多少微秒. 請注意下面的 mSampleRate 其實是 frame rate. 這樣算出來的單位才會是秒, 乘上 106 就變成微秒.

2. 再來就是這個媒體的資料, 宣稱它現在是幾微秒? 其實拿 PTS 算一下就知道了, 這個值叫做 mPositionTimeMediaUs. 我們帥氣地把兩個值相減, 就知道系統時間比較快? 還是媒體時間比較快?

mTimeSourceDeltaUs = mPositionTimeRealUs – mPositionTimeMediaUs

3. 知道兩者差異之後, 我們就可以開始校正了. 我們想要播系統中第 N 秒 (RealTimeUs) 的資料時, 我們把這個 N 秒減去 mTimeSourceDeltaUs, 就知道該播的是媒體中第幾秒 (nowUs) 的資料.

nowUsRealTimeUs – mTimeSourceDeltaUs.

4. 從上下文觀察, 此處的 RealTimeUs 是由 audio 所計算出來的. 於是我們知道 Video 也應該要播媒體中的第 nowUs 秒的資料了. 不過 Video 該不該播出來呢? 要看現在 video 已經準備要播出的那一張的時鐘 (timeUs) 而定. 如果 nowUstimeUs 還小, 那麼表示我這張太早了, 稍微晚一點再播就 OK. 早多少可以接受呢? Android 說凡是早了 10 ms (毫秒) 以上, 都拖個 10 ms 再播!

如果 nowUs 比 timeUs 大, 表示遲到了!

lateness =  nowUs – timeUs.

5. 既然遲到還有甚麼藉口? 只要遲到 40 ms 以上, 一律趕快播! 

6. 如果竟然遲到超過半秒, 說不定 audio 都有問題了!? 所以會強制去 call 一次 AudioPlayergetMediaTimeMapping(&realTimeUs, &mediaTimeUs) 重新取得 realTimUs 和 mediaTimeUs.

以上就是我粗淺的心得, 還請路過的大神幫忙糾正, 順便去救一下 [ref 3] 呼救的那位. 謝謝!

[ref]

1. Android多媒体之OpenCore的A/V同步机制

2. Audio Mutlimedia Framework

3. understanding the logic behind the AV sync in Android 2.2

[後記]

雖然我應該去洗澡睡覺了, 但是還是忍不住講一下八卦. 上面用到微秒和毫秒的地方, 我檢查了一下, 大概沒寫錯. 我記得我大二考電子學第一次期中考的時候, 錯把微秒寫成 10-9, 結果被老師扣了 25 分. 整題計算都對, 只是在 Ans: 後面寫錯單位, 老師還是一分都不給我. 他 (當時還是讀博班的講師) 說: 如果你考博士班資格考 (俗稱 qualify), 錯任何一點點就沒分了. 等我自己考完 qualify, 我確認他是唬爛的…哈! 何況, 己所不欲勿施於人嘛.

我讀 «新巡者»

“新巡者" 是俄國小說家盧基揚年科沉寂多年後的新作, 前幾天去買了一本, 今天終於看完了. 同時間買進的 “通吃iOS及Android:用 HTML5 + Script 就能開發 APP" 當然先丟一邊了. 

小說的第一頁是否能吸引人是關鍵, 新巡者的開頭還是可以吸引我. “一個小孩在機場大吵大鬧不願意上飛機…", 嗯, 這讓我想起了電影 “絕命終結站" 第一集, 值得往下看喔!

這一集的主題, 勉強地說, 就是 “超凡人的存在主義" 吧! 大叫飛機會墜毀而拒絕上飛機的小孩是先知, 先知當然就能預言 “一定會發生的事". 如果某件事一定會發生, 那麼我們可以做什麼嗎? 平凡人大概不能做什麼, 但超凡人呢? 不管是為了自己, 為了祖國, 還是為了全人類; 他們也會試著想要改變必然會發生的事. 

是他們改變得了嗎? 先知的預示一定會發生嗎? 怎麼知道是超凡人干預了未來, 還是預示本來就不準? 要是那些干預只是短暫有效, 但日後會有更大的反撲呢? 這本書的中心思想和前幾部書都不相同, 甚至有自我懷疑和否定的意味, 所以我才會聯想到已經不紅很久的存在主義.

這一集裡面的試著探討上帝與超凡人的關係, 試著解釋吸血鬼的由來, 個人覺得這幾段有點畫蛇添足. 早期的讀者可能試著在某些見面會中, 要求作者回答過這些問題. 不過盧基揚年科大人實在不必像鬼太郎的作者水木茂一樣, 幫每一種鬼怪的來歷都找出理由. 正確的典範有個現成的例子: 我們以前看了 N 集的 X 檔案, 不但始終還是搞不懂外星人的真相是什麼? 還白癡地誤以為下一集就會有答案. 能夠做到這樣就可以了.

不僅是我看出作者受到讀者反饋的影響, 其實連作者在序中也這麼說. 2007 年作者到台灣 “打書" 的時候, 由於深感台灣讀者的熱情, 答應在下一本書中把台灣也列為場景. 果然在本書的 238 頁, 第一人稱的男主角就踏入了中正機場, 並且在故宮博物院和台籍的超凡人范文揚會面, 交換對付幽界的心得. 我在想, 如果我在 2007 年參加台北書展的話, 說不定也能拗他幫我在書中軋一角呢? 比方說: 一個七級的預言家? 

根據本書的定義: 預言家通常看不到自己的未來, 但是先知可以. 預言家預測的事件未必會發生, 先知的預言, 只要被 “凡人" 聽到就一定會發生.

言歸正傳, 撇開作者對超凡人的存在主義, 它的故事還是挺精彩的. 幽界這次化身為有智慧的有形物體 (老虎, 年輕人…等等), 它的能量來自人類的犧牲. 因此天下太平無事的時候, 幽界就會希望先知趕快預言. 因為預言通常不是好事, 而是大災難. 幽界唯一不希望先知說出來的, 就是先知對界的預言. 可想而知, 當先知的預言都和幽界有關, 幽界為了維護自己的生存只好捕殺先知. 這就是本書大致的故事背景.

“新巡者" 的結局, 大家並不難猜到, 超凡人的能量來自幽界; 沒有幽界就沒有超凡人. 而作者不會斷了他寫下一集的財路…

Android APP 對 memory 的要求

剛剛在 Android 4.2 CDD (Compatibility Definition Document) 裡面看到 Android 對 APP 指定了可以給予多少 memory 的參考數字.

不過該表格使用的單位很不直覺, 它定義了 small, normal, large, xlarge 四種螢幕尺寸; 又定義了 ldpi, mdpi, tvdpi, hdpi, xhdpi, xxhdpi 等六種解析度 (DPI = dot per inch).

雖然我們可以顧名思義地推測, xlarge 就是 extra large. hdpi 就是 high DPI 等等. 還是做一張沒有特殊名詞, 直接看數字的表格來參考比較方便.

Screen Size Screen Density (DPI) Application Memory (MB)
426×320/480×320/640×480 120~160 16
213~240 32
320 64
960×720 160 32
213~240 64
320 128

據說真正的視網膜解析度是 477 DPI, 而 iphone 4 超越的視網膜 326 DPI 是指直線的方向而已.

總而言之, 在 Android APP 的世界裡, 還沒有 1080P, 4K2K, 或是超越視網膜這回事. 不然每個 APP 應該可以要個 256 MB 也不為過. 那 PM 就不用再想 "cost down 到一顆 256 MB DRR 有沒有可能?" 這種事了.

不過 Android 的確定義了兩種螢幕類型 (screen types). 一種是固定螢幕解析度 (Fixed-Pixel Device), 例如手機和平版. 所有的視訊都要縮放到它預設的解析度. 另一種類型 (Variable-Pixel Device) 是沒有螢幕, 或是有視訊輸出接口的. 對於後者, Android 就有 HD video 的觀念. 而且它很固執地規定只能有 720P 和 1080P 兩種解析度, 不准支援其它的輸出解析度.

Variable-pixel device implementations MUST support one or both of 1280×720, or 1920×1080 (that is, 720p or 1080p).