劉 馬 飛
(無錫職業技術學院物聯網技術學院 江蘇 無錫 214121)
大客車通常需要在客車內安裝車載播放器,以便在長途行車時提供娛樂節目、電影給乘客觀賞。目前車載播放器通常采使用獨立的DVD播放器或移動硬盤播放機,不但系統成本高,而且DVD播放器更換影片必須使用DVD影碟、移動硬盤播放機更換影片必須通過移動硬盤拷貝,使用不夠方便。
由于基于Android的中控大屏由于具有豐富的娛樂功能、方便與手機和網絡互聯的優點,已經成為高端新能源客車的流行配置。Android在4.2版本以后支持雙屏異顯[1]功能,可以實現在兩塊屏幕上同時顯示不同的內容。因此只需在Android中控大屏的基礎上,額外配備一個車載顯示屏,通過設計相應播放器程序,便可低成本地實現為乘客播放視頻的功能,播放器程序使用Android中控大屏作為播放器操控界面(主屏),視頻播放輸出在車載顯示屏(副屏),而且操作體驗良好;此外由于Android設備方便聯網,使得播放器的影片可通過網絡下載,使用更方便快捷。
本文介紹了利用Android雙屏異顯功能的車載視頻播放器的設計和實現。該車載播放器可低成本地滿足大客車為乘客播放視頻的需要,使用操作靈活簡便,有較廣闊的市場應用價值。
所謂雙屏異顯即在同一軟硬件平臺上實現同時驅動兩塊LCD屏幕,并且這兩塊屏幕所顯示的內容可以不同[1]。Android在4.2版本以后支持雙屏異顯功能,默認情況下兩塊屏幕顯示內容一致,需要基于特定平臺的雙屏異顯方案進行編寫程序方可實現兩個屏幕顯示不同內容。
Presentation 是Google在Android4.2版本以后提供的通用雙屏方案,是Google官方提供的一個特殊的dialog,用來將特定內容顯示到其他非主屏顯示器上,從而輕松實現在兩塊屏幕上同時顯示不同的內容。Presentation在創建時,需要綁定顯示屏,并根據這個目標顯示屏以及其大小來配置context和 resource。目前系統提供通過MediaRouter接口和通過DisplayManager 接口兩種方式將Presentation與目標顯示屏進行綁定[2-3]。本文雙屏實現時采用通過DisplayManager 接口進行顯示屏綁定。
本車載視頻播放器具有以下功能:
(1) 播放視頻顯示輸出在副屏,視頻播放操作控制在主屏進行,主屏可通過應用程序界面和桌面小部件(widget)對播放器進行播放控制。不播放視頻時,副屏顯示歡迎界面。
(2) 桌面程序可顯示當前播放視頻名稱,并可進行播放/暫停、停止、播上一部以及播下一部操作。
(3) 應用程序界面包含播放文件列表供播放選擇,并顯示當前播放文件、播放時間總長以及當前播放時間,并支持通過拖動進度條對變更視頻播放位置。
(4) Android系統開機后,播放器后臺啟動,在副屏顯示歡迎界面。
(5) 播放器監測Android設備外存中可播放的視頻文件的刪除或新增操作,自動變更播放器播放視頻列表。
Android平臺播放音視頻通常使用自帶的組件MediaPlayer,在進行視頻播放時通常還需要利用SurfaceView等設置視頻輸出的界面控件[4-5]。通常Android音頻播放器通過Service實現后臺播放的需求,當Android跳轉到其他程序,播放器程序轉到后臺運行不顯示時,音樂仍然繼續播放[6-7]。而Android視頻播放器由于轉到后臺運行后視頻畫面已不可見,通常不需要支持后臺播放功能[8-9]。與一般視頻播放器不一樣,服務于大客車為乘客播放視頻的雙屏異顯視頻播放器的視頻輸出是在副屏,因此需要通過Service支持后臺播放功能,當主屏操控程序轉到后臺運行不可見時,副屏的視頻仍需持續播放,同時要求Android系統開機后便啟動雙屏顯示功能。依據功能要求,本文設計的車載視頻播放器軟件總體模塊如圖1所示。

圖1 車載視頻播放器軟件總體模塊
模塊各功能如下:
(1) 后臺服務SndDisplayService為本播放器實現的核心,其包括用于播放視頻的MediaPlayer和SurfaceView對象、繼承于Presentation的DifferentDislay類完成副屏的顯示控制、用于接收桌面程序操作的VideoWidgetReceiver、用于視頻文件變動監聽完成維護視頻文件列表的繼承于ContentObserver的VideoObserver類。
(2) AutoStartBroadcastReceiver 繼承于Android核心組件BroadcastReceiver[10],并通過在AndroidManifest.xml中靜態注冊該廣播接收器接收系統開機啟動信號BOOT_COMPLETED,重寫其onReceive方法,在該方法中通過調用startService啟動后臺服務SndDisplayService。
(3) MainActivity 是主操作界面,列表顯示外存所有視頻文件供點擊進行播放,并顯示當前播放的視頻文件信息,播放總時間長度和當前播放時間,通過按鈕選擇暫停/播放、靜音/取消靜音、停止播放、播上一部和播下一部等操作,并可通過拖動進度改變當前播放視頻播放時間。
(4) AppWidget為桌面小部件(widget)[11],可顯示當前正在播放視頻名稱,并可進行相應的暫停/播放、播上一部、播下一部和停止播放操作。
后臺服務SndDisplayService為本播放器實現的核心,AppWidget桌面程序和主程序界面MainActivity均發送操作指令到后臺服務SndDisplayService實現播放控制。本雙屏異顯播放器總體運行流程如圖2所示。

圖2 軟件運行流程
(1) Android系統開機啟動后,靜態注冊的廣播接收器AutoStartBroadcastReceiver接收開機啟動信號,通過startService開啟后臺服務SndDisplayService。
(2) 后臺服務在onCreate操作中完成初始化媒體播放器初始化,同時通過動態兩個內建廣播接收器對象。廣播接收器對象VideoWidgetReceiver用于接收Widget桌面程序的操作指令,廣播接收器對象VideoObserver監測外部存儲視頻媒體庫文件變動維護播放視頻文件列表。后臺服務啟動關閉時,注銷相應的廣播接收器。
后臺服務啟動后,便可通過MainActivity主程序界面和AppWidget桌面程序進行播放器操控。
(3) 播放器主程序界面MainActivity在前臺運行時,通過bindService與后臺服務進行綁定后,主界面通過使用startService對后臺服務進行播放操控,而后臺服務通過綁定操作獲得的回調接口將播放狀態反饋回MainActivity。
(4) AppWidget和后臺服務通過發送廣播方式,進行視頻播放操控以及播放狀態更新。
為了支持視頻后臺播放,因此后臺服務 SndDisplayService類需要包含MediaPlayer和SurfaceView對象、雙屏異顯中完成副屏的顯示控制DifferentDislay類、用于接收桌面程序操作的VideoWidgetReceiver類對象、用于視頻文件變動監聽完成維護視頻文件列表的VideoObserver類、用于記錄播放器狀態的相應變量以及用于向應用程序界面返回相應狀態的回調接口。
后臺服務與AppWidget交互方式如圖3所示。AppWidget桌面程序通過發送廣播的方式發送相應操作指令,如表1所示。后臺服務SndDisplayService內部VideoWidgetReceiver廣播接收器對象的onReceive方法接收操作指令后,對MediaPlayer對象進行相應操作控制。因此需要服務啟動時動態注冊廣播接收器VideoWidgetReceiver對象,接收上述操作指令。

圖3 后臺服務與AppWidget交互方式

指令標記op功能VIDEO_PLAY開始/繼續播放VIDEO_PAUSE播放暫停VIDEO_STOP停止播放VIDEO_NEXT播下一部VIDEO_PREV播上一部
MediaPlayer播放器狀態發生變更后,通過發送廣播方式告知AppWidget桌面程序進行狀態變更以及當前播放視頻,相應廣播動作如表2所示。因此桌面小部件AppWidget需要靜態注冊接收上述廣播動作,并在onReceive方法中進行相應顯示狀態更新。

表2 桌面小部件接收廣播ACTION
后臺服務與主程序界面交互設計如圖4所示。主程序界面MainActivity通過附帶操作指令調用startService實現主界面傳遞后臺服務到進行播放器控制。后臺服務通過重寫onStartCommand方法,接收操作指令并操作MediaPlayer組件完成相應處理。

圖4 后臺服務與主程序界面交互方式
主程序界面提供播放器全部操作,相應操作指令如表3所示。

表3 主程序界面操作指令
雙屏異顯播放器播需要支持后臺播放功能,當主程序界面轉回前臺顯示時,需要獲知后臺播放器當前的播放狀態和播放視頻,因此必需將后臺播放器的狀態信息同步到主程序界面。為了方便后臺播放服務SndDisplayService發回狀態信息,在主程序界面onResume中通過bindService對已經啟動的后臺服務進行捆綁服務操作。后臺服務定義回調接口,主程序界面在服務綁定完成時實現回調接口,在后臺服務中調用該接口,便可實現發回信息給主程序界面。
后臺服務定義PlayStateCallback回調接口用于向主程序界面返回當前播放狀態和播放視頻,PlayTimeCallback回調接口用于返回當前播放時間,以及VideoListCallback回調接口用于對主界面顯示的視頻列表進行更新同步。
后臺服務SndDisplayService啟動時,需要初始化MediaPlayer組件的輸出與副屏進行綁定。首先通過DisplayManager獲取當前顯示屏映射數組,在該映射數組中下標序號0為主屏,序號1為副屏;然后以副屏為參數創建DifferentDislay類對象;最后設置媒體播放器的輸出為副屏的surfaceView控件。
程序定義EntityVideo類記錄每個視頻文件的文件名、播放、文件路徑等信息。Android系統為多媒體類型的文件(圖片、音頻、視頻等)建立了媒體庫,從而完成多媒體數據的維護工作,并可通過ContentProvider提供給其他程序使用。后臺服務SndDisplayService需要在服務啟動時,通過getContentResolver來查詢系統媒體庫中外部存儲所有支持格式的視頻文件,從而構建視頻文件列表。
由于播放文件列表是在后臺服務啟動時通過getContentResolver獲取,當播放器主界面后臺運行時用戶可能新增或刪除了視頻媒體文件,因此需要對視頻文件列表進行維護,避免用戶點擊播放下一部視頻時,視頻文件已經刪除導致播放器異常操作情況。因此需要服務啟動時動態注冊廣播接收器VideoObserver監聽外部存儲中視頻文件的變動情況。
當外部存儲中出現新增或刪除視頻文件時,廣播接收器VideoObserver將可獲知該變動,重寫其onChange方法,在該方法中重新獲取視頻文件列表。如果程序界面正在前臺運行時,通過VideoListcallback回調接口進行界面視頻文件列表更新。
設計程序安裝到RK3288平臺(Android 5.1)上運行,RK3288通過VGA和HDMI連接兩個顯示器,其中VGA連接主顯示屏,HDMI連接副顯示屏。系統開機啟動完成后,將自動完成車載播放器后臺服務初始化工作,開啟雙屏異顯模式,副屏顯示歡迎畫面,如圖5所示。

圖5 系統啟動時副屏歡迎界面
初始化完成后,主屏便可以通過桌面小部件和程序主界面進行播放控制。桌面小部件可進行播放/暫停、上一首、下一首以及停止播放的簡單控制操作以及顯示當前正在播放的視頻名稱,如圖6所示。

(a) 未播放 (b) 正在播放圖6 桌面小部件
程序主界面提供車載播放器的全部控制功能,如圖7所示,副屏顯示當前正在播放視頻輸出畫面如圖8所示。程序主界面以列表方式顯示外部存儲上所有可播放的視頻文件,供用戶進行點擊播放。當開始播放視頻后,程序主界面顯示當前播放影片名稱、當前播放時間,并可通過拖動進度條對調整當前播放影片的播放播放時間。

圖7 播放視頻時主屏程序界面

圖8 播放視頻時副屏
通過程序運行結果分析表明,本設計成功實現了雙屏異顯模式下,車載視頻播放器的相應功能。
本文介紹了利用Android雙屏異顯功能的車載視頻播放器的設計和實現。該車載播放器視頻輸出在副屏,主屏通過主程序界面或桌面小部件進行播放控制,可低成本地滿足大客車為乘客播放視頻的需要。當然如果要將該車載視頻播放器進行實際商用部署,還應該解決以下兩個問題:(1) 由于一般Android應用程序可強行停止,會導致車載播放器程序重啟并初始化為未播放狀態,因此還需要獲得系統權限升級為系統應用,避免異屏雙顯播放器被強行停止。(2) 一般Android系統硬件平臺僅僅包含一路音頻輸出,因此主屏其他程序使用音頻會對副屏視頻播放的音頻造成干擾。因此需要設計含兩條音頻輸出的硬件平臺,方可實現副屏視頻播放音頻不受主屏操作的影響。