摘要:本文主要介紹HTML5 video在android2.2中實現的主要架構和程序流程。
一、實現HTML5 video主要的類
1.? 主要類結構及介紹
??
?
??? 圖1中綠色類為java類,其余為c++類,下面是各個類的具體介紹:
(1) HTMLElement類不是最上層類,其父類可追到為Node類。為了表述方便省去了上面的類繼承結構。該類是一個通用基類,大部分HTML元素都需要繼承該類。
(2) MediaPlayerClient類是一個接口類,HTMLMediaElement以私有方式繼承了部分函數,主要作用是媒體播放狀態改變時通過MediaPlyer在MediaPlayerPrivate中調用。
(3) HTMLMediaElement類完成了video元素大部分行為和屬性的定義。包括audio元素也是繼承該類。
(4)HTMLVideoElement類實現了很少的功能,在android中沒有涉及該類。
(5)MediaPlayer連接播放功能類和媒體元素類的交互類。在HTMLMediaElement中定義了該類的成員指針變量m_player,在完成播放等功能時將會調用該類。
?? 另外在該類定義了一個Media引擎容器,用來保存所有注冊的可提供播放支持的類,比如MediaPlayerPrivate。在需要時會根據媒體資源的需要選擇最好的支持類。
(6) MediaPlayerPrivateInterFace是一個純虛函數類,定義了主要和播放相關的函數。在MediaPlayer中定義了該類的成員智能指針變量m_private。
(7)MediaPlayerPrivate該類繼承了MediaPlayerPrivateInterface類。該類主要用于和HTML5VideoviewProxy類交互。定義了一個HTML5VideoviewProxy類的代理結構成員變量m_glue,用來保存HTML5VideoviewProxy類的實例和方法。
?(8) HTML5VideoviewProxy提供具體的播放。該類通過調用系統系統videoview.java類來實現播放。定義了兩個靜態內部類,一個用來完成具體播放調用。另一個用來完成video poster的下載。另外該類會調用webview.java的chromeclient類成員來實現videoview的顯示和隱藏,默認poster的資源獲取,progress view的獲取。所以要支持HTML5 video,上層webview應用必須重載chromeclient類的相關函數。
2.主要類架構和功能分析
?從上面簡要分析可以看出主要類分了三類:
一類是video元素類(HTMLElement, HTMLMediaElement,HTMLVideoElement)
第二類是架構類和接口(MediaPlayerClient,MediaPlayer,MediaPlayerPrivateInterface);
第三類是具體實現播放功能的類(MediaPlayerPrivate, HTML5VideoviewProxy )。該部分是我可以移植的,可以添加自己的播放類。
? 既然可以實現動態添加功能模塊,那么需要遵守什么。通過源碼可以看出播放類需要實現:提供靜態注冊函數,用來注冊自己;對象創建函數(調用構造函數的函數);支持的數據類型函數;支持的類型和解碼器名字函數。這樣MediaPlay在創建播放類時會根據支持情況選擇。
另外,播放類還必須實現MediaPlayerPrivateInterface中定義的函數,這樣MediaPlay才能通過接口調用具體播放功能;在播放類中也可以調用MediaPlay中的關于播放狀態變化等函數,然后MediaPlay通過MediaPlayerClient接口類調用HTMLMediaElement中具體的實現。將播放狀態返回給媒體元素。
?
二,視頻元素處理流程
??? 在程序完成下面兩個流程后,就可以播放一個視頻資源。
1.? 類實例初始化流程
瀏覽器引擎加載完HTML文檔后,開始解析里面的元素搭建DOM tree, Render tree和加載子資源。在解析video元素時,會創建HTMLVideoElement類對象和對應的RenderVideo對象(因為大部分行為是在基類HTMLMediaElement中完成,所以下圖標識的是HTMLMediaElement)。對于src屬性引擎會調用HTMLMediaElement的loadResource函數,如果沒有該屬性或source子元素,就不會有下面的流程。
?
?
??? 圖2表示了HTMLMediaElement的loadResource函數內部的主要調用流程。首先調用MediaPlay的create函數。然后調用MediaPlayer的load函數,在load函數中會注冊媒體引擎,并根據content type選擇最合適的engine。然后通過engine調用對應播放類的實例創建函數,然后調用播放類的load函數保存媒體資源的url,返回到MediaElement。接著判斷是poater url是否存在,若存在保存到播放類。接下來媒體元素會調用RenderVideo的updateElement函數。在updateElement函數中調用updatePlayer并調用到MediaPlay的setvisible函數,然后調到播放類的setvisible并創建java播放類和設置video poster。Rendervideo是怎么調用到MediaPlay的函數呢。因為在Element對象和Render對象中都保存對方的指針,在MediaElement中又保存了MediaPlyer指針。引擎在創建Element后,便會調用element的attach函數創建對應的Render對象。
2. 播放調用序列
在js中調用video.play()方法時,程序會調用到HTMLMediaElement的play函數。最終會調用到HTML5VideoviewProxy的play函數。
?
?
?
?
?
三、總結:
對于媒體資源的回放,解碼是最大的難題。既然想通過瀏覽器來直接支持視頻播放,那么也必須考慮這個問題。所以在源碼中有Media engine vector的設計,用來根據contentType選擇最佳media engine。在目前android2.2源碼中只有Mediaplayerprivate一個media engine。而該播放類,最終也是調用了系統java接口videoview。并傳給了媒體資源的url。對于解碼的支持完全取決于終端系統。
Android對video元素支持很有限。比如video的controls、autoplay、preload等都沒支持。對于autobuffer的值雖然有設置,但是對于播放器并沒有用到。對于HTML5中定義的很多規則都沒有實現,所以,android對HTML5 video的支持很有限。
在android中HTML5 video有自己的特性。從上面的流程中可以看出,雖然架構設計了通過元素來控制播放和將播放狀態從播放類返回給元素,但在實際播放按鍵響應和控制由videoview完成,js也可以控制播放(比如一開始的play調用)。 播放界面是videoview的controller提供,和引擎里面定義的RenderMediaController沒有關系,可能在chrome中播放出現的控件是該類畫出來的。
??????? 另外,在android中并不支持<audio>元素。