![視覺隨動攝影和移動端播放系統(tǒng)設(shè)計_第1頁](http://file4.renrendoc.com/view10/M00/08/1E/wKhkGWV5KNyANgoRAABDgIl-tsM983.jpg)
![視覺隨動攝影和移動端播放系統(tǒng)設(shè)計_第2頁](http://file4.renrendoc.com/view10/M00/08/1E/wKhkGWV5KNyANgoRAABDgIl-tsM9832.jpg)
![視覺隨動攝影和移動端播放系統(tǒng)設(shè)計_第3頁](http://file4.renrendoc.com/view10/M00/08/1E/wKhkGWV5KNyANgoRAABDgIl-tsM9833.jpg)
![視覺隨動攝影和移動端播放系統(tǒng)設(shè)計_第4頁](http://file4.renrendoc.com/view10/M00/08/1E/wKhkGWV5KNyANgoRAABDgIl-tsM9834.jpg)
![視覺隨動攝影和移動端播放系統(tǒng)設(shè)計_第5頁](http://file4.renrendoc.com/view10/M00/08/1E/wKhkGWV5KNyANgoRAABDgIl-tsM9835.jpg)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
視覺隨動攝影和移動端播放系統(tǒng)設(shè)計摘要隨著無線網(wǎng)絡(luò)的普及,網(wǎng)絡(luò)傳輸速度的提升,移動設(shè)備所占市場份額越來越大,通過移動設(shè)備進行控制的網(wǎng)絡(luò)視頻監(jiān)控發(fā)展迅速。監(jiān)控視頻的播放操作不僅局限在個人電腦上,而且在個人移動設(shè)備上占據(jù)更大份額。如今市場上有很多移動視頻監(jiān)控的產(chǎn)品和配套App,對視頻監(jiān)控的需求很大。本設(shè)計主要研究如何通過樹莓派微型電腦控制攝像頭,樹莓派傳輸監(jiān)控視頻流到云端服務(wù)器,同時,編寫特定Android應(yīng)用程序,遠程Android設(shè)備上對視頻流進行接收并且播放,同時應(yīng)用程序內(nèi)提供控制攝像頭的操作,可轉(zhuǎn)動攝像頭達到監(jiān)控移動物體或人的目的。本設(shè)計主要包括樹莓派GPIO控制,舵機控制,內(nèi)網(wǎng)穿透技術(shù)和Android應(yīng)用程序的編寫。關(guān)鍵詞:樹莓派,視頻傳輸,Android系統(tǒng),HTTP協(xié)議AbstractWiththepopularitycoverageofWi-Finetwork,theincreaseofnetworkspeedandmoreusageofmobiledevices,onlinenetworkmonitoringwithmobiledevicesisdevelopingrapidly.Nowadays,peopledon’tonlywatchthemonitorontheirPCs,butalsopreferviewingthevideostreamontheircellphones.Also,therearemanysoftwareandcorrespondingappsonmobilemonitoring,whichshowsagreatmarket.ThisdesignfocusesonhowtocontrolacamerabyRaspberryPi,streamreal-timevideotoacloudserver,developadesiredAndroidapplicationtoreceivethevideostreamandplayitonAndroiddevices,withaccesstothecamerathatcanchangecameradegreetomonitormovingobjectsorpeople.ThedesignwillinvolveGPIOcontrolonRaspberryPi,servocontrol,NATtraversalandAndroidapplicationdevelopment.Keywords:RaspberryPi,videostreaming,Android,HTTP目錄1. 緒論 71.1. 設(shè)計背景和目的 71.2. 本設(shè)計涉及的相關(guān)技術(shù) 72. 方案設(shè)計與論證 82.1. 基本介紹 82.2. 實現(xiàn)目標(biāo) 82.3. 方案選擇 82.4. 整體結(jié)構(gòu)圖 92.5. 材料清單 102.6. 成品圖 103. 樹莓派系統(tǒng)的初始化和設(shè)置 113.1. 樹莓派簡介 113.2. 樹莓派系統(tǒng)安裝和開機 113.3. 樹莓派無線網(wǎng)絡(luò)設(shè)置 113.4. 樹莓派SSH連接 133.5. 樹莓派遠程桌面控制 164. 攝像頭模塊 184.1. 安裝步驟: 184.2. 攝像頭安裝后成品圖 184.3. 攝像頭操作命令 195. 視頻流處理部分 205.1. 軟件選擇 205.2. MJPG-streamer的安裝和配置 206. 攝像頭舵機部分 236.1. 舵機的簡介 236.2. 舵機的控制原理 246.3. 舵機的安裝 256.4. 舵機的操控 267. 內(nèi)網(wǎng)穿透部分 297.1. 內(nèi)網(wǎng)穿透簡介 297.2. frp在服務(wù)端的安裝配置 297.3. frp在客戶端的安裝配置 317.4. 總體結(jié)構(gòu)圖和運行測試 328. 移動端App的編寫 338.1. Android系統(tǒng)簡介 338.2. Android系統(tǒng)架構(gòu) 338.3. AndroidApp入門 348.4. activity生命周期 368.5. 編寫App界面 388.6. HTTP工具類的編寫 418.7. activity代碼的編寫 428.8. 自定義view的編寫 458.9. App發(fā)送指令操控舵機 478.10. 總體測試與完善 50總結(jié)與展望 52參考文獻 53致謝 54附錄 55MjpegView代碼: 55HttpUtils代碼 70緒論設(shè)計背景和目的社會科技水平不斷發(fā)展,網(wǎng)速提示幅度越來越大。遠程、便攜式的實時視頻監(jiān)控發(fā)展速度也是非常驚人。視頻傳輸和監(jiān)控或者在各行各業(yè)已經(jīng)成為一個很普遍的需求。對于日常家庭,對家庭居住環(huán)境的監(jiān)控也是日益增長的需求,各式各樣的家庭監(jiān)控產(chǎn)品層出不窮。智能手機逐漸普及,智能手機不論系統(tǒng)平臺是iOS或者Android,一般都配備有攝像頭和麥克風(fēng),能夠滿足視頻監(jiān)控的需要,智能手機的普及為視頻監(jiān)控系統(tǒng)帶來了新的趨勢,基于智能手機設(shè)計移動視頻監(jiān)控系統(tǒng)可以不受空間的限制,它的實時性、便攜性和可擴展性很好地滿足了人們對視頻監(jiān)控系統(tǒng)的需求。目前來說,人們使用移動手機平臺大多數(shù)是Android系統(tǒng)和iOS。當(dāng)前移動設(shè)備系統(tǒng)的市場份額中,市場占有率大的依舊是Android系統(tǒng)。根據(jù)以往經(jīng)驗,現(xiàn)在打開應(yīng)用市場搜索,可以找到很多遠程監(jiān)控app。例如我們可以使用一部手機安裝采集端app,作為監(jiān)控采集端,另一手機安裝接收端app,作為監(jiān)控接收端,觀看監(jiān)控視頻內(nèi)容。對于這類app,因為選用的手機攝像頭作為采集端,一般只能放在某一個固定的位置,監(jiān)控的畫面是固定的,不能移動。針對于這一類需求,本設(shè)計探討的主要是如何自己搭建一個基于Android的視頻傳輸系統(tǒng),選擇使用樹莓派控制的攝像云臺進行視頻采集和傳輸,同時監(jiān)控的條件不再滿足于使用本地局域網(wǎng)完成,同樣做到外網(wǎng)可以訪問并控制該攝像云臺,可以遠程觀察到監(jiān)控的情況,同時可轉(zhuǎn)動攝像頭,多方位監(jiān)控。本設(shè)計涉及的相關(guān)技術(shù) 本設(shè)計主要完成基于android的視覺傳輸系統(tǒng),使用云端通訊接口和服務(wù)器,控制樹莓派的攝像云臺運動,監(jiān)控內(nèi)容傳到服務(wù)器,移動端app訪問數(shù)據(jù)進行播放,移動監(jiān)控畫面。具體涉及的技術(shù)方面有樹莓派系統(tǒng)的操作,python語言編程控制樹莓派GPIO,MJPG-Streamer視頻服務(wù)器的搭建,內(nèi)網(wǎng)穿透的應(yīng)用,和滿足本設(shè)計需求的Android應(yīng)用程序的編寫。方案設(shè)計與論證基本介紹本設(shè)計主要由兩個部分組成:控制攝像云臺的樹莓派微型電腦,和Android移動端的應(yīng)用程序。實現(xiàn)目標(biāo)樹莓派驅(qū)動攝像頭模塊,獲取實時的監(jiān)控視頻流樹莓派操控攝像云臺的轉(zhuǎn)動傳輸視頻流到云端服務(wù)器,在外網(wǎng)可以訪問到該實時視頻流,同時同一局域網(wǎng)也可以訪問對應(yīng)的視頻接收端即android應(yīng)用程序,編寫UI界面,能實時觀看到該視頻流android應(yīng)用程序同時提供控制攝像云臺的操作,通過云端服務(wù)器發(fā)送控制命令到樹莓派,移動顯示的監(jiān)控畫面。方案選擇對于攝像頭的選擇,有網(wǎng)絡(luò)USB攝像頭或樹莓派配套的官方攝像頭兩種可以選擇,這兩個在樹莓派上都可以使用。本設(shè)計中選擇樹莓派攝像頭,通過CSI接口軟排線方式接入到樹莓派,整個模塊大小為20x25x10mm,體積小巧。樹莓派有內(nèi)置python攝像頭開發(fā)包Picamera,能對成像或視頻的曝光度,亮度等攝像參數(shù)進行方便地調(diào)節(jié),對應(yīng)的python代碼也簡單。同時樹莓派攝像頭有500萬像素,最高支持1080P/30FPS的視頻錄制,亦能滿足常規(guī)的需要。對于攝像頭操作模塊的選擇,步進電機或者舵機是我們比較好的選擇。最普遍用到的伺服電機系統(tǒng)是舵機,同時也是低端的伺服電機系統(tǒng)。舵機對應(yīng)的英文是Servomotor,人們一般簡稱為Servo。舵機將PWM信號與滑動變阻器的電壓相比對,通過硬件電路實現(xiàn)固定控制增益的位置控制。電機、傳感器和控制器,構(gòu)成完整的伺服電機系統(tǒng)。舵機價格不貴,結(jié)構(gòu)小但是比較合一,那相應(yīng)的缺點也是存在的,就是精度低,位置鎮(zhèn)定能力較差,但對于實現(xiàn)低端需求,是足夠的,包括本設(shè)計的需求。所以本設(shè)計選擇舵機,主要原因在于價格便宜,淘寶上一個9G舵機價格12塊,可節(jié)省成本。對于云端服務(wù)器,現(xiàn)在大型互聯(lián)網(wǎng)公司都有提供云產(chǎn)品服務(wù),例如阿里云,騰訊云,國外的有亞馬遜AWS。本設(shè)計出于成本考慮,筆者購買了阿里云學(xué)生優(yōu)惠的輕量應(yīng)用服務(wù)器,上限帶寬有10MB/s,作為學(xué)習(xí)目的。對于移動端應(yīng)用程序,本應(yīng)用對性能要求不是很高,主流android系統(tǒng)版本也都可以運行本應(yīng)用。對于樹莓派的選擇,選擇的是當(dāng)前最新版的樹莓派版本3B+,不用插入無線網(wǎng)卡,內(nèi)置了Wi-Fi模塊,可以直接接入Wi-Fi網(wǎng)絡(luò),與手機或其他家庭設(shè)備處于同一局域網(wǎng)下。對于樹莓派中對視頻傳輸和視頻流的處理,有motion,mjpg-streamer,本設(shè)計選用mjpg-streamer,因為相比motion,能控制的視頻參數(shù)和輸入輸出比較多,同時畫面延遲低。讓視頻通過外網(wǎng)訪問則使用內(nèi)網(wǎng)穿透技術(shù),用的是frp庫,比較簡單,一般家庭也沒有可用的公網(wǎng)IP??刂茦漭蓴z像頭轉(zhuǎn)動的命令,樹莓派端使用flask這一pythonweb框架,接收命令,Android端使用HTTP協(xié)議,發(fā)送POST請求到樹莓派整體結(jié)構(gòu)圖材料清單一臺樹莓派3B+(5V電源、16G內(nèi)存卡),一個樹莓派配套攝像頭兩個TowerProSG90舵機,一個雙軸尼龍云臺支架(用于固定攝像頭和轉(zhuǎn)動),若干條杜邦線一臺Android手機阿里云輕量應(yīng)用服務(wù)器成品圖樹莓派系統(tǒng)的初始化和設(shè)置樹莓派簡介樹莓派,可以說是世界上最小的臺式機或微型電腦,由英國的慈善組織“樹莓派基金會”研發(fā)出來,艾·邇濮敦是該開發(fā)項目的領(lǐng)導(dǎo)人。在2012年3月,樹莓派正式發(fā)售,大小尺寸就一張銀行卡差不多,擁有的基本功能卻和普通電腦絲毫不差。樹莓派英文名是RaspberryPi,基于ARM機構(gòu),以普通存儲卡為存儲硬盤,但樹莓派這一塊很薄的主板卻配備有幾個USB接口和一個網(wǎng)線接口,所以樹莓派能外接網(wǎng)線、鼠標(biāo)和鍵盤,同時還配備有高清HDMI輸出口和視頻模擬信號的輸出口。因此,像在樹莓派上自己開發(fā)一個小的程序或者是小游戲,再自己外接上顯示器,便可以實現(xiàn)玩游戲的功能,播放視頻或音樂也是非常簡單,功能豐富。樹莓派系統(tǒng)安裝和開機因為新到手的樹莓派不會帶有存儲卡,需要自己額外購買,那么沒有硬盤這一存儲介質(zhì),自然也沒有內(nèi)置的操作系統(tǒng),用戶需要自己下載鏡像文件,手動安裝樹莓派系統(tǒng)。第一步先去樹莓派官網(wǎng)下載系統(tǒng)鏡像文件,同時需要準(zhǔn)備一張16G內(nèi)存卡作為樹莓派的硬盤,內(nèi)存卡容量可以更大,但至少要16G比較好,16G能滿足本設(shè)計的需求。系統(tǒng)下載完后,需要使用win32diskimager鏡像安裝工具,對剛下載完的鏡像文件刷入到SD卡中(需要SD卡讀卡器),刷系統(tǒng)之前,一般需要對SD卡進行快速格式化操作。刷入系統(tǒng)到SD卡后,會發(fā)現(xiàn)SD卡所顯示的容量低于預(yù)期。這是因為在Windows系統(tǒng)中只能顯示出FAT格式的boot分區(qū),只有幾十個MB,更大的分區(qū)是Linux分區(qū),Windows系統(tǒng)是無法看到的,這并不影響樹莓派系統(tǒng)的工作。樹莓派無線網(wǎng)絡(luò)設(shè)置刷好系統(tǒng)后,先不直接把SD卡插入樹莓派中,還需要對系統(tǒng)中的一些文件加以修改。因為樹莓派直接開機的話,在沒有外接顯示器的情況下無法對之操作,而想通過遠程桌面控制樹莓派的話需要先讓樹莓派處于同一局域網(wǎng)下。那么,需要做的就是讓樹莓派接入當(dāng)前Wi-Fi網(wǎng)絡(luò)下。樹莓派在為開啟的狀態(tài)下,用戶需要事先修改樹莓派boot目錄下的wpa_supplicant.conf文件,在該文件里配置Wi-Fi的SSID和密碼。配置完成后,樹莓派開機啟動后會自行讀取wpa_supplicant.conf配置文件,連接上Wi-Fi。操作方法如下:先將樹莓派系統(tǒng)刷入SD卡,電腦上讀該SD卡,在boot分區(qū),也就是電腦上可以看到的boot目錄下,直接新建一個文件,命名為wpa_supplicant.conf,以下面的配置模式寫入內(nèi)容,然后保存wpa_supplicant.conf文件:country=CNctrl_interface=DIR=/var/run/wpa_supplicantGROUP=netdevupdate_config=1network={ssid="WiFi-A"psk="12345678"key_mgmt=WPA-PSKpriority=1}network={ssid="WiFi-B"psk="12345678"key_mgmt=WPA-PSKpriority=2scan_ssid=1}#ssid:WiFi網(wǎng)絡(luò)的ssid,即WiFi顯示出來的名稱#psk:WiFi的連接密碼#priority:當(dāng)存在多個可用WiFi時,優(yōu)先級判斷,數(shù)字越大連接上該WiFi的優(yōu)先級越高(不要填寫負數(shù),負數(shù)沒有意義)#scan_ssid:連接隱藏(即沒有開啟ssid廣播)的Wi-Fi時需要指定該值為1如果Wi-Fi沒有設(shè)置連接密碼network={ssid="你的無線網(wǎng)絡(luò)名稱(ssid)"key_mgmt=NONE}如果你的Wi-Fi使用WPA/WPA2加密network={ssid="你的無線網(wǎng)絡(luò)名稱(ssid)"key_mgmt=WPA-PSKpsk="你的Wi-Fi密碼"}樹莓派SSH連接配置好網(wǎng)絡(luò)這一部分,還需要再開啟樹莓派的SSH服務(wù)(默認(rèn)是關(guān)閉的)。沒開啟該服務(wù)之前,想通過SSH與樹莓派建立通信自然是失敗的。手動啟用SSH的方法是:在boot目錄新建一個空白的、不要有文件類型后綴的、命名為ssh的文件。樹莓派啟動運行后,系統(tǒng)能掃描檢測到該文件,則開始啟用SSH連接服務(wù)。然后我們自己用軟件或路由器管理頁面獲取樹莓派內(nèi)網(wǎng)IP地址,應(yīng)用SSH協(xié)議,與樹莓派建立通信。Wi-Fi信息配置好之后,可以正式地把SD卡插入到樹莓派,連接電源,開機。開機一段時間后,樹莓派就會根據(jù)我們之前的Wi-Fi配置,自動連接上當(dāng)前的Wi-Fi網(wǎng)絡(luò),這樣我們同一網(wǎng)絡(luò)下的設(shè)備便有機會訪問到該樹莓派。我們可以使用網(wǎng)段掃描工具如AdvancedIPScanner,這類軟件會自動檢測電腦所在的局域網(wǎng)下所有的設(shè)備,對應(yīng)名稱和制造商都能顯示出來。筆者電腦使用的安全防護軟件有提供掃描同一網(wǎng)絡(luò)下設(shè)備的功能,筆者便直接使用,如下圖可以看到樹莓派的地址是78因為要開始對樹莓派進行操作,在沒有外接顯示屏的情況下,我們采用遠程桌面的方式連接并控制樹莓派。雖然樹莓派現(xiàn)在處于開機狀態(tài)了,但是還沒有開啟遠程桌面所需要的相關(guān)服務(wù),還無法進入到樹莓派的桌面進行操控。那么,在這里我們要和樹莓派建立最初的一個連接就是通過SSH連接樹莓派,之前的新建ssh文件就是為了這一步而準(zhǔn)備。SSH是由IETF網(wǎng)絡(luò)工作組開發(fā)的SecureShell的首字母縮寫,它就是一種協(xié)議,是安全的且基于應(yīng)用層。SSH最初出現(xiàn)于UNIX系統(tǒng),SSH幾乎可以在所有UNIX平臺上運行,例如包括Linux,AIX,Solaris,DigitalUNIX等,后來很快移植擴展到其他操作平臺,多個平臺上都有SSH客戶端。Windows電腦上下載一個SSH終端軟件,筆者在這里使用的是PUTTY。界面如下:輸入樹莓派的地址,即剛才獲取到的78端口填寫為22,即樹莓派默認(rèn)暴露出來的SSH端口。信息填寫好,點擊連接,會彈出一個警告框,點擊確定。然后進入黑窗口命令行界面,以初始用戶名pi和密碼raspberry登錄會話,建立通信。登陸后如圖:樹莓派遠程桌面控制接下來一步,便是啟動樹莓派的遠程桌面服務(wù),因為樹莓派系統(tǒng)本身已經(jīng)有自帶REALVNCServer的服務(wù),我們要做的就是啟動它,輸入命令vncserver-2這個命令的意思就是啟動一個vncserver桌面號制定為2,同時還可以跟上其他參數(shù),如桌面的分辨率等等。然后,我們在電腦上下載vncviewer,再次輸入樹莓派的ip內(nèi)網(wǎng)地址加上開啟的桌面號2:如圖,這樣就進入了樹莓派的桌面,我們就能使用電腦上的鼠標(biāo)和鍵盤來操控樹莓派了。為了后期方便,我們打算讓樹莓派開機就自啟動該遠程桌面服務(wù),而不用每次都先連接SSH,輸入命令去開啟這個服務(wù)。這樣每次開機后,便可以直接打開vncviewer操控樹莓派。配置方法如下:首先sudonano/etc/init.d/vncserver(即在/etc/init.d/目錄下創(chuàng)建編輯一個名為vncserver的文件)然后復(fù)制下面的內(nèi)容右鍵粘貼進去#!/bin/sh#SettheUSERvariabletothenameoftheusertostartvncserverunderexportUSER='pi'(這里就是對應(yīng)的登錄用戶的名字,默認(rèn)pi)evalcd~$USERcase"$1"instart)#啟動命令行。此處自定義分辨率、控制臺號碼或其它參數(shù)。su$USER-c'/usr/bin/vncserver-depth16-geometry1024x768:2'echo"StartingVNCserverfor$USER";;stop)#終止命令行。此處控制臺號碼與啟動一致。su$USER-c'/usr/bin/vncserver-kill:2'echo"vncserverstopped";;*)echo"Usage:/etc/init.d/vncserver{start|stop}"exit;;esacexit然后Ctrl+O回車保存,Ctrl+X退出文本編輯器然后修改權(quán)限:sudochmod755/etc/init.d/vncserver然后添加開機啟動項:sudoupdate-rc.dvncserverdefaults最后重啟樹莓派:sudoreboot至此,開機自啟動的工作便完成了。攝像頭模塊安裝步驟:1. 找到CAMERA接口(主板上印有該字眼),掀起深色膠帶。2. 用手指輕輕撬動起兩邊的接口擋板。3. 撕掉攝像頭模塊上的塑料保護膜。確保黃色部分的PCB(有字的一面)正確安裝。4. 將排線插入CAMERA接口,把有藍色的一面,對向網(wǎng)線接口方向。攝像頭安裝后成品圖攝像頭安裝好后如圖:工作時,led紅燈會亮,如圖:注意:把攝像頭的排線接入樹莓派的時候,不要“熱插拔”。因為攝像頭對靜電很敏感,安裝攝像頭時要確保樹莓派是斷電狀態(tài),攝像頭操作命令接著執(zhí)行:$sudoraspi-config通過鍵盤方向鍵,去啟用攝像頭模塊,重啟樹莓派。設(shè)置完成后,可以對攝像頭進行測試工作。樹莓派提供了三個相關(guān)的操作命令:raspistill、raspivid、raspistillyuv。常用的是這兩個:raspistill和raspivid,前者用于獲取圖像,后者用于獲取視頻。1)用rasptill獲取一張圖片,如:raspistill-oimage.jpg-rot180參數(shù)o輸出到文件,參數(shù)rot讓圖片旋轉(zhuǎn)180度。2)用raspivid獲取視頻raspivid-ovideo.h264-t10000捕捉10秒H.264壓縮格式的視頻,保存到文件video.h264。視頻流處理部分軟件選擇樹莓派系統(tǒng)下有兩個對視頻處理比較好的軟件:motion和mjpg-streamer:motion是一個免費開源的Linux系統(tǒng)下的視頻監(jiān)控軟件,用C語言寫成,可用于運動檢測。它可以監(jiān)視一個或多個攝像頭的視頻信號,并且能夠檢測到圖像的主要部分是否已經(jīng)改變,當(dāng)它檢測到正在發(fā)生運動時還可以保存視頻)。motion是命令行驅(qū)動的,占用空間小,CPU使用率低,可以作為守護進程運行。MJPG-streamer可以從Linux-UVC兼容的網(wǎng)絡(luò)攝像頭,文件系統(tǒng)或其他輸入插件中獲取JPG,并通過HTTP將它們作為M-JPEG流式傳輸?shù)骄W(wǎng)頁瀏覽器上、VLC和其他軟件。經(jīng)過資料查證,motion的卡頓較大,二十多秒的延遲基本無法接受。而MJPG-streamer就好很多。雖然motion實現(xiàn)更簡單,但最終選用MJPG-streamer實現(xiàn)視頻流的傳輸。MJPG-streamer的安裝和配置首先安裝相應(yīng)的依賴庫sudoapt-getinstallsubversionlibjpeg8-devimagemagicklibv4l-devcmakegit從GitHub下載MJPG-streamer,并編譯,安裝gitclone/jacksonliam/mjpg-streamer.gitcdmjpg-streamer/mjpg-streamer-experimental/makeallsudomakeinstallMJPG-streamer提供了多個輸入源和輸出源的選擇,支持的輸入源有6種:input_file,input_http,input_opencv,input_ptp2,input_raspicam,input_uvc支持的輸出源有4種:output_file,output_http,output_viewer,output_zmqserver例如,如果接上普通的免驅(qū)動USB攝像頭,執(zhí)行命令:./mjpg_streamer-i"./input_uvc.so"-o"./output_http.so-w./www"如果是樹莓派攝像頭則使用以下命令./mjpg_streamer-i"./input_raspicam.so"-o"./output_http.so-w./www"對于樹莓派攝像頭的輸入源控制,MJPG-streamer也提供了很多參數(shù):[-fps|--framerate]...:設(shè)置視頻幀率,默認(rèn)為5幀/秒
[-x|--width]:幀捕獲的寬度,默認(rèn)為640
[-y|-height]:幀捕獲高度,默認(rèn)480
[-quality]:設(shè)置JPEG質(zhì)量0-100,默認(rèn)為85
[-usestills]:使用靜止模式而不是視頻模式
[-preview]:啟用全屏預(yù)覽
-ISO:設(shè)置捕獲ISO
-vs:打開視頻穩(wěn)定功能
-ev:設(shè)置EV補償
-ex:設(shè)置曝光模式(參見raspistillnotes)
-awb:設(shè)置AWB模式(參見raspistill說明)
-rot:設(shè)置圖像旋轉(zhuǎn)(0-359)-stats:計算每張圖片的圖像統(tǒng)計數(shù)據(jù)(降低噪點)
-drc:動態(tài)范圍補償級別(參見raspistillnotes)
-hf:設(shè)置水平翻轉(zhuǎn)
-vf:設(shè)置垂直翻轉(zhuǎn)筆者最終輸入的命令是:./mjpg_streamer-i"./input_raspicam.so-vs-x320-y240"-o"./output_http.so-w./www",即啟用打開視頻穩(wěn)定功能,雖然可能丟幀,但確保了視頻傳輸?shù)牧鲿承?,寬度和高度分別為320和240,原因是減少網(wǎng)絡(luò)帶寬的壓力。輸出是以HTTP形式訪問,即最終會在樹莓派架設(shè)起一個本地服務(wù)器,以這種形式輸出也方便以后的內(nèi)網(wǎng)穿透服務(wù),將視頻暴露到外網(wǎng)中,使用外網(wǎng)網(wǎng)址也可以訪問到視頻流。執(zhí)行命令后,輸入78:8080則可以看到實時視頻。筆者78是我樹莓派局域網(wǎng)內(nèi)的IP地址。如圖:也可以輸入78:8080/?action=stream直接獲取實時視頻流的網(wǎng)址進行觀看,可在網(wǎng)頁瀏覽器或VLC播放器中直接輸入,該地址以后會用到。效果如圖:如果有多個輸入源,可以通過下面的方式獨立地訪問每個視頻流:78:8080/?action=stream_078:8080/?action=stream_1如果是查看當(dāng)前時刻的靜態(tài)JPEG圖像,可以直接訪問http://78:8080/?action=snapshot攝像頭舵機部分舵機的簡介舵機,主要是由外殼、電路板、驅(qū)動馬達、減速器與位置檢測元件所構(gòu)成,是一種位置伺服驅(qū)動器,適用于那些需要角度不斷變化并可以保持的控制場景。它的工作原理是由接收機向轉(zhuǎn)向器發(fā)出信號,通過電路板上的IC驅(qū)動無核心馬達開始轉(zhuǎn)動,通過減速器將動力傳遞給擺臂,通過位置檢測器傳遞回信號,判斷是否已經(jīng)到達定位。位置檢測器實際上是一個可變電阻器,轉(zhuǎn)動伺服時,電阻值會發(fā)生變化。通過檢測電阻值,可以知道旋轉(zhuǎn)角度。舵機有兩個主要的性能指標(biāo):扭力和轉(zhuǎn)速,齒輪組和電機關(guān)乎這兩個性能的重要因素。扭力是指舵機能轉(zhuǎn)動或扭動產(chǎn)生的力有多少。在5V的電壓下,標(biāo)準(zhǔn)舵機的扭力是5.5千克/厘米(75盎司/英寸)。轉(zhuǎn)速是指從舵機一個角度轉(zhuǎn)到另一個角度要多長時間。在5V電壓下,舵機標(biāo)準(zhǔn)轉(zhuǎn)速是0.2秒移動60度。標(biāo)準(zhǔn)舵機圖解舵機的控制原理在了解如果控制舵機之前,需要知道PWM(PulseWidthModulation)技術(shù),全名也叫做脈沖寬度控制技術(shù)。PWM是一種對模擬信號電平進行數(shù)字編碼的方法。通過使用高分辨率計數(shù)器,方波的占空比被調(diào)制以編碼特定模擬信號的電平。PWM信號仍然是數(shù)字信號,因為在任何給定時間,滿量程DC電源要么完全,要么完全關(guān)閉。電壓或電流源以重復(fù)脈沖序列ON或OFF施加到模擬負載。當(dāng)DC電源施加到負載時,電源關(guān)閉時斷電。只要帶寬足夠,任何模擬值都可以使用PWM進行編碼。舵機控制信號為50Hz,即脈寬調(diào)制(PWM)信號的周期為20ms,脈沖寬度為0.5ms-2.5ms,相對應(yīng)舵盤的位置為0-180度,線性變化。也就是說,為了給它提供一定的脈沖寬度,其輸出軸將保持相應(yīng)的角度,無論外部扭矩如何變化,它都會改變輸出直到給出另一個寬度的脈沖信號。角度到新的相應(yīng)位置。轉(zhuǎn)向器內(nèi)部有一個參考電路,用于產(chǎn)生周期為20ms,寬度為1.5ms的參考信號。同時存在一個比較器,其將所施加的信號與參考信號進行比較以確定方向和尺寸,從而產(chǎn)生電動機的旋轉(zhuǎn)信號。我們想在樹莓派上操控舵機轉(zhuǎn)動,樹莓派本身又無法直接輸出模擬電信號,我們便可以使用PWM(脈寬調(diào)制)方法來模擬這一點。樹莓派或者是其他單片機一個引腳只能輸出兩個特定的電平——高電平和低電平。在樹莓派上大多的GPIO都是高電平3.3V,低電平0V。如果想要一個輸入2V,樹莓派是沒有辦法直接設(shè)置引腳的電平來達到輸出2V的,那么我們就要使用PWM來輸出介于低電平和高電平之間的電壓。我們制作一個固定頻率的數(shù)字信號,在那里我們將改變脈沖寬度,將“轉(zhuǎn)換”改為“平均”輸出電壓的電平。頻率本身不是重點,而是“占空比”,即脈沖“高”的時間除以波周期之間的關(guān)系。例如,假設(shè)我們在樹莓派的GPIO上產(chǎn)生一個50Hz的脈沖頻率。周期(p)將是頻率的倒數(shù)或20ms(1/f)。本設(shè)計使用的TowerProSG90舵機,這是市面(淘寶)上比較常見的一款舵機轉(zhuǎn)角,從0度到180度。SG90舵機有三條不同顏色的線:紅線,棕線和黃線。這三條線的作用是:紅線VCC,棕線GND,黃線控制線。所以我們是操控黃線來控制舵機。查看TowerProSG90文檔后我們可以得知其占空比與轉(zhuǎn)動角度的關(guān)系:在周期20ms下:角度占空比0.5ms0度;2.5%1.0ms45度;5.0%1.5ms90度;7.5%2.0ms135度;10.0%2.5ms180度;12.5%占空比關(guān)系圖舵機的安裝通過在淘寶購置相應(yīng)的塑料云臺,以及購買的舵機配套的塑料擺臂,用鉗子對一些過長的擺臂進行長度的修改,用螺絲組裝在一起,一個擁有兩自由度的舵機便可以搭設(shè)完成。因為攝像頭有一定重量,只靠塑料云臺的重量壓不住攝像頭,于是筆者再取用一塊小的萬能電路板于云臺底部組裝在一起,加重底部重量,當(dāng)舵機轉(zhuǎn)動時,保證舵機本身不會被甩動。最終攝像云臺成品圖如下:注意的是,為了方便定位舵機,筆者在把兩個舵機組裝進去之前,先直接接入樹莓派,用編程驅(qū)動把兩個舵機的角度都調(diào)在90度的位置(控制代碼在下面介紹),然后再調(diào)正云臺。這樣的舵機初始位置比較好操控和辨別。舵機的操控通過編程樹莓派GPIO口,提供電源,可以接地,輸出控制,三個引腳實現(xiàn)對某一個舵機轉(zhuǎn)動的操控。樹莓派的GPIO引腳集成在樹莓派的電路板上。用戶或開發(fā)者可以控制它們的行為,以允許它們從傳感器讀取數(shù)據(jù),并控制LED,電機和顯示器等組件。老型號的樹莓派有26個GPIO引腳,而較新的型號例如筆者使用的樹莓派3B+都有40個。下圖是樹莓派40Pin引腳圖,其中有些IO口如0V和5V這種無法用于編程。操作GPIO引腳的話,python代碼中需指定以什么模式查找引腳編號,不同模式對應(yīng)的引腳編號,如上圖寫著的Physical,如果以Physical模式的引腳號去查找,對應(yīng)就是GPIO.setmode(GPIO.BOARD)。如果以BCM模式的引腳號去查找,代碼即是GPIO.setmode(GPIO.BCM)。對于兩個舵機,我分別選用了BCM模式下6和13的IO口,通過公母杜邦線接入到樹莓派。如圖:下面編寫對舵機操控的測試代碼,讓某一個舵機來回不停地從0度旋轉(zhuǎn)到180度。從上面的分析可以得知改變占空比的話,0度對應(yīng)2.5,180度對應(yīng)12.5,那么傳入ChangeDutyCycle()的參數(shù)數(shù)值就在2.5-12.5之間。具體代碼如下:#-*-coding:utf-8-*-#!/usr/bin/envpythonimportRPi.GPIOasGPIOimporttimeimportsignalimportatexitatexit.register(GPIO.cleanup)servopin=6GPIO.setmode(GPIO.BCM)#選用BCM模式GPIO.setup(servopin,GPIO.OUT,initial=False)p=GPIO.PWM(servopin,50)#50HZp.start(0)#time.sleep(2)while(True):foriinrange(0,181,3):#以3度為變化的間隔p.ChangeDutyCycle(2.5+10*i/180)#設(shè)置轉(zhuǎn)動角度time.sleep(0.02)#等該20ms周期結(jié)束p.ChangeDutyCycle(0)#歸零信號time.sleep(0.02)foriinrange(181,0,-3):#循環(huán)進行p.ChangeDutyCycle(2.5+10*i/180)time.sleep(0.02)p.ChangeDutyCycle(0)time.sleep(0.02)至此,舵機正常運行,在下文的代碼中,會根據(jù)特定指令調(diào)整舵機方向,則需要往程序中傳入?yún)?shù)。這部分代碼會下文中提及。我們的視頻流服務(wù)器和攝像云臺已經(jīng)架設(shè)起來,樹莓派本機只要輸入網(wǎng)址或者同一局域網(wǎng)下的其他設(shè)備輸入該網(wǎng)址都可以訪問。但為了外網(wǎng)設(shè)備也可以遠程訪問到局域網(wǎng)內(nèi)的服務(wù)器,我們需要用到內(nèi)網(wǎng)穿透技術(shù)。內(nèi)網(wǎng)穿透部分內(nèi)網(wǎng)穿透簡介內(nèi)網(wǎng)穿透(NATtraversal),也叫做NAT穿透。內(nèi)網(wǎng)穿透主要解決了TCP/IP中的一個常見問題:使用了NAT設(shè)備的私有TCP/IP網(wǎng)絡(luò)中的主機之間如何建立連接。目前有許多用于內(nèi)聯(lián)網(wǎng)滲透的技術(shù),但它們都不是毫無缺點,因為內(nèi)網(wǎng)穿透的行為是沒有一個標(biāo)準(zhǔn)。這些技術(shù)中的每一種通常都具有外部網(wǎng)絡(luò)可訪問的云服務(wù)器,并且服務(wù)器使用可以從世界上任何地方訪問的IP地址。內(nèi)網(wǎng)穿透常用的工具有:Ngrok,Natapp,F(xiàn)rp,Lanproxy,Spike,花生殼。本設(shè)計中選用有提供中文技術(shù)文檔的frp。 對于本設(shè)計,主要就是將在局域網(wǎng)內(nèi)的視頻流服務(wù)器暴露到外網(wǎng),通過在云端服務(wù)器開啟端口,再對接到本地視頻服務(wù)器的端口,再設(shè)置一個外部訪問云服務(wù)器的端口,即可實現(xiàn)外網(wǎng)收看內(nèi)網(wǎng)視頻流的效果。frp在服務(wù)端的安裝配置首先從github上下載frp的release版本,阿里云服務(wù)器(服務(wù)端)和樹莓派(客戶端)都要安裝,同時確保兩邊安裝的版本是一致的。然后,在阿里云服務(wù)器上配置端口,除去已有的端口,筆者新增了三個端口,分別是7000,6081,9999,協(xié)議都是TCP。如圖所示:我們可以嘗試先直接訪問6081這個端口,當(dāng)然現(xiàn)在是不可用的。(48是我服務(wù)器的公網(wǎng)IP)解壓目錄,有6個文件,分別是frpc、frpc_full.ini和frpc.ini屬于客戶端用到的文件,本設(shè)計中即在樹莓派中要用到;frps、frps_full.ini和frps.ini屬于服務(wù)端用的文件,本設(shè)計中即在阿里云服務(wù)器中要用到。我們將frps及frps.ini放到具有公網(wǎng)IP(阿里云服務(wù)器)的機器上。將frpc及frpc.ini放到處于內(nèi)網(wǎng)環(huán)境(樹莓派)的機器上。所以在阿里云服務(wù)器上面,我們只需要配置frps.ini文件就行,打開編輯如下內(nèi)容:[common]bind_port=7000vhost_http_port=60817000和6081都是筆者在服務(wù)器新開設(shè)的端口,7000會作為服務(wù)器和樹莓派通信的一個端口,6081端口是服務(wù)器暴露在外面供訪問的端口。隨后啟動啟動frps,在frp的目錄下運行以下命令:./frps-c./frps.ini此時再次訪問48:6081,瀏覽器返回的頁面應(yīng)該如下圖,證明服務(wù)端已經(jīng)成功運行,但是客戶端還沒有相應(yīng)的配置好,故frp返回頁面找不到的提示信息,是正常的反饋提示。frp在客戶端的安裝配置樹莓派客戶端也是相同的配置方法,修改frpc.ini文件,已知我服務(wù)器的公網(wǎng)IP為48,那么在文件中,配置如下:[common]server_addr=48server_port=7000[ssh]type=tcplocal_port=22remote_port=6000[web_cam]type=httplocal_port=8080custom_domains=48可以看到common里面的server_port配置的便是7000,于frps配置中的bind_port=7000相對應(yīng)。在web_cam里面,type為hhtp,local_port為8080,是本地視頻服務(wù)器的訪問端口。custom_domains屬性是服務(wù)器的域名網(wǎng)址(如),如果該服務(wù)器有申請域名的話,但本設(shè)計中筆者并沒有為該服務(wù)器再額外購買域名,則該屬性仍然填上服務(wù)器的公網(wǎng)IP地址。同樣,在frp的目錄下運行以下命令:./frpc-c./frpc.ini如果客戶端已經(jīng)正確配置并且運行的話,會得到以下信息:總體結(jié)構(gòu)圖和運行測試frp架構(gòu)圖web_cam已成功開啟proxy外網(wǎng)訪問到視頻流已經(jīng)實現(xiàn)移動端App的編寫Android系統(tǒng)簡介Android是大家熟識的基于Linux內(nèi)核、開源移動操作系統(tǒng),由Google的開放手持設(shè)備聯(lián)盟引領(lǐng)并且進行長期開發(fā)和維護。主要應(yīng)用于智能手機和、平板電腦與其他便攜式設(shè)備和觸摸屏設(shè)備。在2010的時候,Android操作系統(tǒng)已經(jīng)嶄露頭角,非常火熱,超越當(dāng)時的諾基亞Symbian系統(tǒng),成為全球最大的智能手機操作系統(tǒng)。Android系統(tǒng)版本從2008年最初的1.0,一路更新到現(xiàn)在的9.0版本,在系統(tǒng)安全,權(quán)限管理,功能特性上,有越來越多的更新和支持。在Android編程中,涉及到的編程語言有C,Java,Kotlin,Python等。Android系統(tǒng)架構(gòu)Android系統(tǒng)大致劃分為四層架構(gòu):Linux內(nèi)核層、系統(tǒng)運行庫層、應(yīng)用框架層和應(yīng)用層。其中內(nèi)核層,系統(tǒng)運行庫層,應(yīng)用框架層對于常規(guī)app開發(fā)者來說接觸的地方不多,對于ROM開發(fā)者或底層開發(fā)者可能比較常用,相對來說編程開發(fā)難度也比較大,需要對整個系統(tǒng)架構(gòu)有比較深的認(rèn)識才能據(jù)此進行二次開發(fā)。對于我們常規(guī)的app開發(fā)者來說,需要更注重應(yīng)用層的東西。所謂應(yīng)用層,我們安裝在手機上或者買來手機就自帶的所有應(yīng)用程序,都屬于該層。例如系統(tǒng)一般都自帶有聯(lián)系人app、撥號盤app,短信app等,或是我們自己在應(yīng)用市場下載的app,亦或是開發(fā)人員開發(fā)的應(yīng)用程序。Android系統(tǒng)架構(gòu)圖AndroidApp入門對于本設(shè)計的App,即屬于上面提及到的應(yīng)用層,大多數(shù)時候的開發(fā)也是基于這一層進行的。對于Android應(yīng)用的開發(fā),開發(fā)者使用的IDE(集成開發(fā)環(huán)境)有Eclipse和AndroidStudio。不過Eclipse已經(jīng)過時很久,Google很早就停止了對Eclipse的支持,Google官方開發(fā)的AndroidStudio雖然早期有較多問題,但現(xiàn)在已經(jīng)是很成熟的一個IDE。安裝完開發(fā)AndroidStudio,開發(fā)Android應(yīng)用還需要JDK,AndroidSDK,安裝過程在此不贅述,而且安裝AndroidStudio的時候有提供這些選項,基本可以一步到位。在新建完一個新的Android項目后,可以看到項目目錄如圖:項目的目錄有很多,大的目錄可以看到有manifests,java,generatedJava,res和Gradle。manifests存放AndroidManifest.xml,這個文件是項目配置的清單文件,我們在這個清單文件中注冊我們定義的四大組件,同時也需要給應(yīng)用程序添加各種各樣的權(quán)限(如網(wǎng)絡(luò)權(quán)限,存儲讀寫權(quán)限)。java目錄是我們存放所有java代碼的地方(當(dāng)然現(xiàn)在Android開發(fā)也支持使用Kotlin語言開發(fā),但本設(shè)計使用java),該目錄是我們會主要使用的一個目錄。generatedJava是IDE為我們自動生成的java文件,開發(fā)中我們并不需要對它做改到。res目錄下則存放應(yīng)用程序所需要的布局文件,各種資源,如圖片,字符串的國際化等。Gradle是AndroidStudio用來構(gòu)建項目的工具,基于Groovy的領(lǐng)域特定語言來聲明項目設(shè)置,拋棄了傳統(tǒng)基于XML的配置方式。對于Android開發(fā),需要大致了解下Android有四大組件,分別為activity、service、contentprovider、broadcastreceiver。應(yīng)用程序中,一個Activity通常就是獨立的可見視圖,它上面可顯示一些控件,可以監(jiān)聽并處理用戶的單擊、長按等點擊事件。如果在Activity之間傳遞數(shù)據(jù)或一個Activity想啟動另外的Activity,需要用到Intent。一個service,相比Activity來說,一般擁有更長生命周期,但是用戶是看不到界面的,service可用來開發(fā)后臺類程序。典型的例子有后臺播放語音導(dǎo)航信息的地圖app或者正在后臺下載視頻的下載器。地圖導(dǎo)航app中的某個activity在被用戶按home鍵之后,可調(diào)用Context.startService()來啟動一個service,從而保持雖然app不可見,但是后臺進行著導(dǎo)航路線的計算,同時播放導(dǎo)航語言。系統(tǒng)也將保持這個service一直執(zhí)行,直到這個service運行結(jié)束。另外,開發(fā)中也可以調(diào)用Context.bindService()方法,綁定到另外的service上(如果該service未運行則將啟動它)。很多是市面上的流氓app,特別是國產(chǎn)應(yīng)用,如百度全家桶那些,很有可能開了很多進程或服務(wù)相互?;睿粋€被kill了,另外一個還在,并且重新激活剛被kill的服務(wù),所以會極大增大android手機的耗電量。當(dāng)連接到一個service之后,還可以service提供的接口與它進行通訊。注意這里有一個對應(yīng)關(guān)系,如果啟動服務(wù)用的是startService()方法,那要停止該服務(wù)就要用Context.stopService()方法。ContentProviders管理對結(jié)構(gòu)化數(shù)據(jù)集的訪問。它可以封裝這類數(shù)據(jù),并提供類型安全的數(shù)據(jù)機制。Contentproviders是標(biāo)準(zhǔn)的接口,它能將一個線程中的數(shù)據(jù)與其他線程中的運行的代碼進行連接。也就是說Contentproviders支持IPC(跨進程間)的訪問。當(dāng)我們想要在從Contentprovider中拿到自己開發(fā)應(yīng)用的數(shù)據(jù)或是其他app的數(shù)據(jù),需要使用ContentResolver對象與Contentprovider的子類對象相連接。該provide對象會接收數(shù)據(jù),resolver對象會響應(yīng)請求,返回結(jié)果。BroadcastReceiver是一種在android開發(fā)中普遍用的傳播信息的機制,可以在不同應(yīng)用程序之間傳播。主要用來監(jiān)聽系統(tǒng)或者應(yīng)用發(fā)出的廣播信息,像上文提到的流氓app進程長駐,互相保活需要用的就是注冊廣播,在有一個進程被殺死時,通知另一個進程,另一個進程根據(jù)廣播信息做相應(yīng)的邏輯或業(yè)務(wù)處理,例如再次激活被殺死進程。BroadcastReceiver正常來講用來傳輸較小型的數(shù)據(jù)。例如,android開機時,開機了是一種信息,很多程序要做到開機自啟動服務(wù),就需要去監(jiān)聽“開機”這一廣播信息。還有如網(wǎng)絡(luò)狀態(tài)切換,如Wi-Fi斷開,變成4G數(shù)據(jù)網(wǎng)絡(luò)在連接,直播類app可能就會彈出提示,通知用戶是否繼續(xù)使用數(shù)據(jù)流量觀看直播。BroadcastReceiver并沒有可視化界面,但是當(dāng)它收到某個通知或信息之后,BroadcastReceiver可以通過推送一條通知,啟動某個服務(wù),或啟動某個Activity,達到提醒用戶的目的。activity生命周期本設(shè)計中,主要用到的四大組件就是activity。在此,需要著重介紹下activity的生命周期。對于某一個Android應(yīng)用,對用戶來說,最直觀就是看到android應(yīng)用的界面,或者說可見的窗口。與用戶直接進行交互的,一般也就是Activity。對于android應(yīng)用中每一個Activity,都必須要在AndroidManifest.xml配置文件中聲明,否則系統(tǒng)無法啟動該Activity,因為識別不了。當(dāng)只有一個單一activity的app啟動時,activity的生命周期的流程如下:正常情況下,一個活動啟動到結(jié)束會執(zhí)行的方法依次為:onCreate()onStart()onResume()onPause()onStop()onDestroy()(1)onCreate:這是Activity生命周期進行的第一個方法,也是我們在android開發(fā)中非常常用、以及很必需的生命周期方法。它本身進行Activity的一些初始化工作,比如使用setContentView加載布局,對一些控件和變量進行初始化等。此時Activity還在后臺,不可見。(2)onStart:因為一個東西創(chuàng)建出來,還不一定啟動了,activity也是如此。這是繼onCreate之后activity生命周期會執(zhí)行的第二個方法,但是啟動后此時對用戶來說暫時是看不到的,用戶無法點擊觸控,無法交互Activity。我們可以將一些Activity的初始化工作放在這個方法里面,但是初始化工作放在onCreate方法中仍然是更常見的做法以及開發(fā)習(xí)慣。(3)onResume:resume是繼續(xù),從字面意思理解,也可以知道這個方法的用處。此時Activity經(jīng)過前兩個階段的初始化工作已經(jīng)完成。Activity在這個階段已經(jīng)出現(xiàn)在前臺,用戶可以見到。(4)onPause:pause當(dāng)Activity被切出去,例如用戶點擊了home鍵,或者用戶自己的操作,要跳到另一個Activity,亦或是用戶點擊返回鍵,應(yīng)用正常退出時都會執(zhí)行這個方法。此時Activity在前臺而且對用戶來說還是可見的。在這個方法里面開發(fā)者簡單地保存下數(shù)據(jù),但必須是小型數(shù)據(jù)。因為onPause方法必須在半秒內(nèi)沒有執(zhí)行完成,否則Activity會被強制關(guān)閉。高級優(yōu)化開發(fā)時,可以多關(guān)注這個方法。(5)onStop:停止,此時Activity已經(jīng)不可見了,但是具體某個Activity的實例仍然占用著內(nèi)存空間,內(nèi)存還沒有被釋放。這個方法的主要工作是做一些資源的回收工作。(6)onDestroy:這個階段Activity被銷毀,對用戶來說已經(jīng)不可見了,可以釋放資源。(7)onRestart:Activity在這時再次可見,可能會觸發(fā)的場景如:重新當(dāng)用戶按Home鍵切出app后又切回來。編寫App界面對于我們app的界面,首先必不可少的就是接收視頻的一個view,我們看到視頻中的畫面,想要移動畫面時,界面中也需要有上下左右這4個方向按鈕,通過點擊這4個按鈕來操控舵機,同時移動畫面。App的最終截圖大致如此:對于實現(xiàn)這樣的效果,筆者選擇根布局為線性布局,5個按鈕的形式以gridlayout的形式組合起來,嵌套在根布局中,和觀看視頻的自定義view是同一個層級。界面代碼大致如下:<LinearLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.noname.cameraviewer.MjpegViewandroid:id="@+id/cameraview"android:layout_width="match_parent"android:layout_height="0dp"android:background="#000"/><GridLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:layout_weight="1"android:columnCount="3"android:rowCount="3"><Buttonandroid:id="@+id/bt_capture_img"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_row="1"android:layout_column="1"android:text="@string/capture"/><Buttonandroid:id="@+id/bt_up"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_row="0"android:layout_column="1"android:text="@string/up"/><Buttonandroid:id="@+id/bt_down"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_row="2"android:layout_column="1"android:text="@string/down"/><Buttonandroid:id="@+id/bt_left"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_row="1"android:layout_column="0"android:text="@string/left"/><Buttonandroid:id="@+id/bt_right"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_row="1"android:layout_column="2"android:text="@string/right"/></GridLayout></LinearLayout>布局中我們使用了自定義view,關(guān)于自定義view的java代碼會在下文提及,這里先直接引入,引入的時候需要全包名加類名的方式來使用這個view。同時對所有view都添加一個id,id的作用是為了在java代碼中能查找到這些view,才能操控這些view。例如點擊事件觸發(fā)時,判斷是哪個按鈕被點擊,或者對mjpegview的設(shè)置。gridlayout的使用,一開始是設(shè)置為縱3列,橫3列,即剛好是一個九宮格的布局。在本界面中,我們只有5個按鈕,對應(yīng)的按鈕位置設(shè)置,例如UP按鈕,設(shè)置android:layout_row="0"和android:layout_column="1",因為這兩個屬性的起始值都是從0開始,0是代表了第一行或第一列。在界面代碼中,gridlayout的節(jié)點設(shè)置了android:layout_weight="1"的屬性,在mjpegview不用設(shè)置,該屬性默認(rèn)便為0。這樣做的目的是讓控制按鈕的部分在始終能在activity中顯示出來,因為在小屏幕設(shè)備上,可能由于高度不夠,先渲染了mjpegview后,下面的按鈕也可以顯示出來,但會顯示不全,底部按鈕可能在activity之外,無法點擊。那么,layout_weight屬性在線性布局中,表示了某布局在該線性布局中的占比。因為gridlayout為1,觀看視頻的mjpegview占比為0,那會優(yōu)先渲染gridlayout,確保gridlayout可以始終先占有空間,gridlayout顯示完成后,再根據(jù)屏幕剩余的空間去加載視頻view,而視頻的view我們可以通過傳進去的參數(shù)調(diào)整分辨率或view高度來控制。HTTP工具類的編寫在app中我們通過HTTP請求方法中的POST方法,向樹莓派發(fā)送命令。那么,我們寫一個簡單的HTTP工具類對網(wǎng)絡(luò)操作進行封裝。把該類命名為HttpUtils。因為是工具類,方法都定義為static類型,可以直接調(diào)用。里面編寫三個方法:postData(Map<String,String>params,Stringencode,StringtargetUrl)調(diào)用該方法發(fā)送POST請求到服務(wù)器并返回服務(wù)器信息。參數(shù)params是請求體內(nèi)容,encode是參數(shù)編碼格式,targetUrl是目標(biāo)URL。方法返回的是服務(wù)器的返回信息。getRequestData(Map<String,String>params,Stringencode)調(diào)用該方法來包裝請求信息。參數(shù)param是請求體的參數(shù),encode是編碼格式,方法返回的是請求體信息。handleResponseResult(InputStreaminputStream)調(diào)用該方法來處理服務(wù)器的響應(yīng)結(jié)果(將輸入流轉(zhuǎn)換為字符串)。參數(shù)inputStream是服務(wù)器的響應(yīng)輸入流,方法返回的是服務(wù)器響應(yīng)的結(jié)果字符串。該工具類完整代碼詳見附錄。activity代碼的編寫MainActivity實現(xiàn)View.OnClickListener接口,實現(xiàn)接口,就要重寫接口里定義的方法,在這里具體需要實現(xiàn)的是onClick(Viewview)方法,響應(yīng)app內(nèi)所有按鈕的點擊事件。然后定義對應(yīng)的IP地址(這里我們先直接填寫樹莓派內(nèi)網(wǎng)IP作為測試),以及四個String常量,即我們最終POST到樹莓派的指令,樹莓派通過判斷哪個字母進行舵機哪個方向的轉(zhuǎn)動。privatefinalstaticStringSERVO_UP="U";privatefinalstaticStringSERVO_DOWN="D";privatefinalstaticStringSERVO_LEFT="L";privatefinalstaticStringSERVO_RIGHT="R";privateStringcommand;//傳遞方向指令的參數(shù)privateStringservoUrl="78:5000/";接下來在onCreate方法中,執(zhí)行加載布局文件的方法setContentView()。查找到布局中所有view的id,查找到這些按鈕。如對UP按鈕的設(shè)置:ButtonbtUp=findViewById(R.id.bt_up);btUp.setOnClickListener(this);同時對視頻view進行參數(shù)設(shè)置,這些參數(shù)在view中定義為public方法,所以外部可以訪問到。cameraView.setAdjustHeight(true);cameraView.setMode(MjpegView.MODE_FIT_WIDTH);cameraView.setUrl("78:8080/?action=stream");cameraView.setRecycleBitmap(true);同時,我們再重寫activity方法中的onResume,onPause,onStop,分別執(zhí)行的camerview的開啟流和停止流的方法。@OverrideprotectedvoidonResume(){cameraView.startStream();super.onResume();}@OverrideprotectedvoidonPause(){cameraView.stopStream();super.onPause();}@OverrideprotectedvoidonStop(){cameraView.stopStream();super.onStop();}我們再定義控制舵機轉(zhuǎn)動的方法,注意因為該方法涉及到網(wǎng)絡(luò)操作。而在android系統(tǒng)中,網(wǎng)絡(luò)請求被認(rèn)為是一個耗時的操作,如果直接就在UI主進程執(zhí)行的話,是會拋出異常的。所以在activity執(zhí)行該方法時,需要在開啟一個子線程,包住方法代碼。按鈕點擊后調(diào)用controlServo(),controlServo()會開啟一個新線程,然后我們調(diào)用工具類HttpUtils中的靜態(tài)方法postData(),該方法會向服務(wù)器提交表單,表單中只有一個字段ctrl(與之對應(yīng)的服務(wù)器代碼在下面介紹),即代碼中的params.put("ctrl",command),去傳遞代表舵機轉(zhuǎn)動方向的字符串?dāng)?shù)據(jù)給服務(wù)器,同時在log中打印出服務(wù)器返回給我們的響應(yīng)結(jié)果。publicvoidcontrolServo(){newThread(newRunnable(){@Overridepublicvoidrun(){Map<String,String>params=newHashMap<String,String>();params.put("ctrl",command);try{Stringpost_result=null;post_result=HttpUtils.postData(params,"utf-8",servoUrl);Log.i("POST_RESULT",post_result);}catch(MalformedURLExceptione){e.printStackTrace();}}}).start();}最后重寫onClick方法,通過swich語句加view.getId()方法判斷哪個按鈕被點擊,對command進行相應(yīng)賦值。@OverridepublicvoidonClick(Viewview){switch(view.getId()){caseR.id.bt_capture_img:break;caseR.id.bt_up:command=SERVO_UP;controlServo();break;caseR.id.bt_down:command=SERVO_DOWN;controlServo();break;caseR.id.bt_left:command=SERVO_LEFT;controlServo();break;caseR.id.bt_right:command=SERVO_RIGHT;controlServo();break;}}}至此,activity代碼介紹基本完成。自定義view的編寫筆者新建一個了自定義view來播放視頻。該view可以接收url參數(shù),可以設(shè)置填充的模式(如原始的畫面比例,或者是高度適應(yīng),或者是寬度適應(yīng))。這里的技術(shù)要點是以Bitmap對象保存視頻當(dāng)前幀的圖像,并通過一個繼承Thread的內(nèi)部類,不斷更新該bitmap對象,實現(xiàn)當(dāng)前幀不斷更新,達到視頻實時更新呢和播放的效果。本項目中,直接在MainActivity同個包目錄下新建class(本項目工程量比較小,如果實際項目比較大,應(yīng)該劃分好不同的包,作為一個好的開發(fā)習(xí)慣。如自定義view應(yīng)該新建一個包名為view,并將該class放在該目錄下)。對于自定義view,首先就是要繼承父類View。該自定義view定義的類成員變量主要有:privateContextcontext;privateStringurl;privateBitmaplastBitmap;privateMjpegDownloaderdownloader;privatefinalObjectlockBitmap=newObject();privatePaintpaint;//定義繪制view的畫筆privateRectdst;privateintmode=MODE_ORIGINAL;//默認(rèn)模式privateintdrawX,drawY,vWidth=-1,vHeight=-1;privateintlastImgWidth,lastImgHeight;privatebooleanadjustWidth,adjustHeight;privatebooleanisRecycleBitmap;privatebooleanisUserForceConfigRecycle;根據(jù)變量名,可以得知該變量對應(yīng)的作用。對于每一個view,無論是android系統(tǒng)提供的還是我們自己實現(xiàn)的,Android系統(tǒng)都是會去執(zhí)行view類里三個重要的方法,這三個方法讓view在屏幕上計算位置,繪制渲染,在app中顯示出來。這三個方法是onMeasure()、onLayout()和onDraw()。我們自定義view時,一般也需要重寫這三個很重要的方法。measure過程根據(jù)View的類型分為兩種情況:單一View時:只測量自身一個View;ViewGroup時:對ViewGroup視圖中所有的子View都進行測量。本設(shè)計繼承的是view,即單一view的情況。單一View的measure過程如下示:measure():基本測量邏輯的判斷;調(diào)用onMeasure()。onMeasure方法代碼比較多,MjpegView的完整代碼詳見附錄。measure過程結(jié)束后,視圖的大小就已經(jīng)測量好了,接下來就是layout的過程了。不過對該view來說,這里的場景不需要重寫onLayout方法,接著繼續(xù)重寫onDraw方法:@OverrideprotectedvoidonDraw(Canvasc){synchronized(lockBitmap){//同步該代碼塊,阻塞其他訪問該對象的線程if(c!=null&&lastBitmap!=null&&!lastBitmap.isRecycled()){if(isInEditMode()){}elseif(mode!=MODE_ORIGINAL){c.drawBitmap(lastBitmap,null,dst,paint);//繪制bitmap}else{c.drawBitmap(lastBitmap,drawX,drawY,paint);}}else{Log.d(tag,"Willnotdraw,canvasisnullorbitmapisnotreadyyet");}}}內(nèi)部類MjpegDownloader中重寫run方法,涉及到網(wǎng)絡(luò)操作,用BufferedInputStream接收輸入流,以及還有對請求header的正則匹配操作。內(nèi)部類代碼比較多,完整代碼見附錄。App發(fā)送指令操控舵機通過post命令,樹莓派再次借助frp這一內(nèi)網(wǎng)穿透的服務(wù),同時再開啟一個服務(wù)器,同時暴露出一個端口,用來接收來自手機端的POST命令。那么為了再運行一個本地服務(wù)器
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 施工現(xiàn)場施工防恐怖襲擊制度
- 現(xiàn)代科技在學(xué)生心理健康教育中的應(yīng)用前景
- 科技教育與家庭教育的融合策略
- 拆除工程專項施工方案和技術(shù)措施
- 個人與單位借款合同模板大全
- 專業(yè)拳擊教練聘任合同
- 產(chǎn)學(xué)研合作協(xié)議合同新
- 個人雇傭合同樣本
- 個人購房抵押借款合同范本
- 個人車輛投資共享合同2025
- 《新時代公民道德建設(shè)實施綱要》、《新時代愛國主義教育實施綱要》知識競賽試題庫55題(含答案)
- 2024-2030年中國假睫毛行業(yè)市場發(fā)展趨勢與前景展望戰(zhàn)略分析報告
- 2019-2020學(xué)年七年級(上)期末數(shù)學(xué)試卷2附解析
- 德國職業(yè)學(xué)校教育質(zhì)量保障體系研究
- 第3篇 助跑 項目六 異形芯片分揀與安裝講解
- 傳統(tǒng)戲劇藝術(shù)與人工智能的創(chuàng)新傳播渠道
- 2024年越南天然食用香料與色素行業(yè)現(xiàn)狀及前景分析2024-2030
- 實體瘤療效評價標(biāo)準(zhǔn)(RECIST11)
- 教案-中國書法史
- 隧道施工-緒論(使用)
- 2024年湖南高速鐵路職業(yè)技術(shù)學(xué)院單招職業(yè)適應(yīng)性測試題庫附答案
評論
0/150
提交評論