MTP之前幾年幾乎沒有人在用。有啦,Pictbridge是架在PTP之上,所以PTP還有存在的價值,但是近幾年來Pictbridge也漸漸地消失在市場中了....理由我猜是相容性問題吧。
MTP的用途跟MSC類似,不同的地方wiki解釋的很清楚,我就不講了。
PTP規格是ISO標準(ISO15740),提到ISO,第一個就要想到[錢]。是的,下載它是要錢地。但是呢,MTP規格下載是不用錢的...。所以現在大家都用MTP規格在玩。
請注意一點,MTP只是個資料交換的通訊協定,所以要透過哪種載具(transport)去傳輸這些資料,是每個載具要定義的,如果要透過USB傳輸MTP資料,請參考[Still Image Capture Device Definition]這份規格書。跟MSC很像,這份文件只定義MTP資料要透過那些Endpoint傳輸,以及容器的格式。資料內容的話,請參照[Media Transfer Protocol]這份規格書。
先談[Still Image Capture Device Definition]。
這份文件很簡單,MTP主要透過Bulk-In,Bulk-In,跟 Interrupt-In來傳輸資料。一般情況下,Bulk-In跟Bulk-In就夠了,Interrupt-In主要是提供一些即時資訊給HOST知道,沒提供也不會怎樣。
每筆MTP資料之前都要加上一個header,這邊叫container,格式如下:
基本上HOST一定是發Command Block,Device回Response Block,Data Block則是看哪一方要發資料,這沒甚麼好說的。
Class Request則是有四個,Cancel、Get Extended Event Data、Device Reset、跟Get Device Status。
- Cancel有點特別,它通常用來取消某次的傳輸。為什麼說他很特別?因為這是MTP特有的問題。在MTP規格內,如果要傳一個大檔案,因為要等很久,使用者有可能會在中途取消。問題來了,MTP規格沒有定義取消方式,所以只能在Transport Layer做這個處理。
- Get Extended Event Data:我沒用過...。
- Device Reset:沒有甚麼特殊。
- Get Device Status:我看過唯一有用的是在Cancel之後,HOST會用這個Request來問狀態。
接下來是[Media Transfer Protocol]。
MTP資料格式全部都是little endian,比較特殊的有字串跟Array:
- 字串:它是所謂的Pascal String,但是用的是unicode 16 little endian編碼。第一個byte表示後面有幾個[字元],這個字串還必須包含'\0'這個字元。跟strlen()不同,要小心。
- Array:第一個integer表示後面還有幾個element。
- 日期:它是個字串,格式是"YYYYMMDDThhmmss.s"。既然它是個字串,所以它也遵循字串的編碼規定。".s"可有可沒有。
基本上MTP的流程是Command -> Data -> Response。在MTP規格裡,Command稱為[Operation]。而每個物件(或稱為檔案)都必須有個獨一無二的ID,規格稱為[Handle],整個通訊協定裡,雙方基本上是在處理這些Handle。請注意,物件並不是只有檔案,還包含目錄,這就是為什麼要叫物件而非檔案。
透過這些資訊,大概的物件交換協定也可以猜得出來。我這邊直接用規格來說明:
- HOST用GetObjectHandles命令取得DEVICE端的物件列表。
- HOST取得列表後,可以用GetObjectInfo命令取得每個物件的資訊。
- HOST可以用GetObject命令取得該物件的資料內容。
- 如果要取得某個物件的縮圖,可以用GetThumb命令。
- 要刪除某個物件,可以使用DeleteObject命令。
- GetObjectPropSupported、GetObjectPropValue跟GetObjectPropDesc則是MTP特有命令,它可以支援更多關於物件的屬性。因為GetObjectInfo的屬性是固定的,所以只能用額外的命令去新增屬性。
當然,當USB MTP裝置一插上HOST時,HOST可以用GetDeviceInfo取得這個裝置的資訊,並用GetDevicePropDesc跟GetDevicePropValue取得這個裝置支援的屬性。
等等,上面沒提到如何寫入物件到裝置啊?這有點複雜,因為物件一向都是裝置提供對應的ID,HOST根本沒法存取一個不存在的物件啊?所以這個動作要分兩個命令,第一個是SendObjectInfo跟DEVICE說要新增一個物件以及它的屬性,然後DEVICE會把這個物件的ID放在Response內,之後HOST再用SendObject把這個物件的資料傳給DEVICE。這樣做很引發一些問題,例如不能重傳或從某個地方開始傳。傳到一半要取消也是很麻煩。
實作MTP基本上不難,但是有幾點很麻煩:
- 相容性問題。這個基本上無解,因為MTP是微軟主推的規格,其他作業系統可能不太想支援太多。就我所知,至少MAC OS對它的支援就不是太好。有一些行為跟Windows差很多。
- 多檔案處理:因為所有物件都是用Handle ID來表示了,所以DEVICE必須處理Handle ID所對應的實體檔案轉換。所以一個映射表免不了,當檔案多到99999時候,這個映射表會有多大?存取速度呢?
- WHCK。這個真的很煩。
No comments:
Post a Comment