用wifi直連(p2p)實現遙控照相

現在具有wifi遙控功能的照相機已經很多,Canon和Nikon都有。最近兩三年發佈的新相機幾乎都支持WIFI傳圖和遙控功能。本文介紹用wifi p2p方法實現兩臺android手機遙控拍攝的方案。
有關wifi直連(p2p)的公開技術資料已經有很多,此處不再贅述有關細節,僅對方案要點作一些說明,實現細節可以參照源代碼

使用兩臺手機,一臺作爲相機,安裝camera app,在wifi p2p group中,擔當group owner。
另一臺作爲遙控器,安裝controller app,在wifi p2p group中,擔當group client。
系統構成
在兩臺手機間建立wifi直連後,可以進行雙向通信,爲了實現遙控拍攝,需要通過wifi p2p傳遞以下信息:

  • 連接狀態,在兩臺手機上顯示連接成功與否。當收到對方手機信息時,在己方手機上顯示連接成功符號。
  • 相機端向遙控端回傳鏡頭取得的瀏覽圖像,這實際上就是相機端取得的視頻流,傳送到遙控端用於取景。
  • 遙控端發出的拍攝指令,用來按下相機端的快門。
  • 如果需要,還可以把相機端拍攝的照片回傳到遙控端,目前程序中沒有實現,應該難度不大。

這些傳送信息,用三種形式表示:
第一種是字符串,用於傳送連接狀態、拍攝指令。
connected表示已經連接
disconnected表示斷開連接
capture表示拍攝
第二種是用ByteBufferTransfer類封裝的圖像數據,包括承載圖像的字節數組byte[]、以及從相機端取得圖像的各種相關信息。
第三種是文件,可以用於傳送已經拍攝的照片。

程序由三部分組成:camera app、controller app和comm lib。系統架構採用mvp官方模板。

一、camera app管理控制相機的打開、關閉、拍攝、預覽視頻取得、編碼壓縮等機能,並且以group owner的身份建立wifi p2p連接group。
camer app的主架構

二、controller app以group client身份同相機端建立wifi p2p連接,取得相機端傳送的字節流,解碼成視頻,顯示在遙控端手機上。需要時,通過wifi p2p連接向相機端發出拍攝指令。
controller app的主架構
三、comm lib是一些共通的類和方法。

由於在程序中使用了一些回調和監聽,代碼的可讀性不太好。爲了便於理解,在此簡單介紹最核心的部分。

ByteBufferTransfer
該類包含了圖像數據的字節數組,以及視頻編解碼相關的信息MediaCodec.BufferInfo,每一個ByteBufferTransfer的實例,代表視頻中的一幀圖像。爲了能夠通過wifi p2p傳送,ByteBufferTransfer必須實現Serializable接口。

ByteBufferTransferTask
這是專用於傳送ByteBufferTransfer實例的後臺異步任務。

DirectBroadcastReceiver
本系統中有關wifi p2p的核心部分是DirectBroadcastReceiver,在相機端和遙控端都要用到,這是一個廣播接收器,用於處理系統產生的wifi p2p事件,有以下四種:

  • WIFI_P2P_STATE_CHANGED_ACTION
    Wifi P2P狀態變更時發生,用於指示 Wifi P2P 是否可用。
  • WIFI_P2P_PEERS_CHANGED_ACTION
    Wifi P2P節點list變化時發生,此時需要用WifiP2pManager.requestPeers方法請求獲取Wifi P2P節點list,請求的結果由onPeersAvailable監聽器獲得。
  • WIFI_P2P_CONNECTION_CHANGED_ACTION
    WIFI_P2P節點連接狀態變化時發生,此時需要用intent.getParcelableExtra方法取得EXTRA_NETWORK_INFO情報,如果處於連接狀態,可以進一步取得WifiP2pInfo,WifiP2pInfo包含羣組是否建立、誰是羣主、羣主的地址等信息。
  • WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
    本機設備信息變化時發生,此時需要重新獲取本機設備信息。

CameraWifiServerService、ControllerWifiServerService
在相機端和遙控端各有一個IntentService,類名是CameraWifiServerService和ControllerWifiServerService,用來處理通過wifi p2p接受到的信息,分別對字符串、圖像字節數組、文件做出相應處理。

mStateCallback
這是在MainPresenter中定義的CameraDevice.StateCallback的實現,是openCamera必須的參數之一。在相機端打開照相機時,執行createCameraPreviewSession方法,在該方法中實現以下動作:

  • 建立相機預覽用的Surface
  • 創建作爲預覽的CaptureRequest.Builder
  • 將textureView的surface作爲CaptureRequest.Builder的目標
  • 根據視頻編碼類型創建編碼器
  • 實例化MediaCodecCallback
  • 格式化編碼器
  • 啓動編碼器
  • 創建CameraCaptureSession,該對象負責管理處理預覽請求、拍照請求和傳輸請求。

視頻流編解碼使用的是H264 Vga(640x480)格式,如果改爲H265格式,應該沒有什麼難度, android體系對於H265視頻編解碼已經有了成熟的支持,問題是三年前生產的手機大部分不支持H265編碼。

MediaCodecCallback
這是在相機端實現的MediaCodec.Callback。當視頻編碼器完成一幀圖像的編碼時,通過onOutputBufferAvailable取得ByteBuffer數據,從中提取字節數組,注入ByteBufferTransfer的實例中,然後啓動ByteBufferTransferTask,把ByteBufferTransfer的實例通過wifi p2p連接傳送到對方。

DecoderCallback
這是在遙控端實現的MediaCodec.Callback。通過onInputBufferAvailable,當視頻解碼器的輸入緩衝區空閒時,把通過wifi p2p接收到的字節數組注入解碼器,啓動視頻解碼進程。

MediaCodecCallback和DecoderCallback都是用回調實現的視頻編解碼器,優點是代碼簡潔、效率高,缺點是安卓SDK 21以前的版本不支持。

MediaCodecAction
該類用於視頻解碼器的準備、啓動和釋放。在準備時用mediaCodec.configure方法把遙控端手機的TextureView的Surface與視頻解碼器的輸出綁定,在遙控端就可以看到相機端取得的圖像。

把以上這些模塊結合到android架構中,實現手機的遙控拍攝。

需要說明的是,由於各個手機品牌對於wifi p2p的定製深度不一,這個系統在一些手機上並不能正常運行。準確原因筆者尚未找到,也許是程序的BUG,希望高手大俠指點迷津。

camera app可以運行的安卓SDK版本是23-27。
controller app可以運行的安卓SDK版本是21-27。

源程序請參照 用wifi直連(p2p)實現遙控照相的源代碼

歡迎指摘、建議、問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章