利用NDI SDK實現(xiàn)Android端視頻流的發(fā)送

摘要:本文從NDI 提供的SDK(Android)出發(fā),通過Android Studio進(jìn)行開發(fā)粗悯,實現(xiàn)了Android手機端對NDI視頻流的發(fā)送和接收俄占,并在局域網(wǎng)里測試辐烂,打通了Android端和PC端通過NDI互相串流及鏡像顯示。

關(guān)鍵字:NDI验残、JNI捞附、C++、Cmake胚膊、NDK故俐、NSD、Service紊婉;

一药版、前言

????????NDI是Newtech公司(目前被Vizrt收購)基于IP網(wǎng)絡(luò)里面?zhèn)鬏敎\壓縮視頻流的方案,NDI作為一款純軟件標(biāo)準(zhǔn)喻犁,相比于RTMP槽片、RTS等視頻流協(xié)議,它具有更低的延遲(理論延遲只有16行)肢础、4K和高清的實時兼容还栓、支持Alpha通道的傳輸、以及Tally传轰、元素?fù)?jù)剩盒、控制協(xié)議等、能夠快速的構(gòu)建信號的擴展和連接慨蛙,任意NDI流辽聊、任意分辨率纪挎,只要在一個局域網(wǎng)里,就能被發(fā)現(xiàn)和接收,并統(tǒng)一的進(jìn)行輸出。

????????相比于ST2110的標(biāo)準(zhǔn)舶掖,NDI是能夠更有效的降低制作成本,對于廣電制作烤蜕,NDI有“Full NDI”支持輸出更高的碼率,對于手機端和PC端迹冤,NDI有“NDI HX”支持輸出較低的碼率讽营,兩者在局域網(wǎng)內(nèi)互相兼容,都能被發(fā)送和接收到叁巨。

????????本次項目開發(fā)的時候還是基于NDI 4.0的SDK版本斑匪,目前NDI已經(jīng)支持5.0,NDI 5.0向下兼容4.0,此次介紹的一些方法和庫锋勺,同樣適用于5.0版本,具體功能可參考官方文檔NDI SDK文檔蚀瘸。

二、Android端NDI框架的設(shè)計與搭建

2.1庶橱、導(dǎo)入NDI SDK并構(gòu)建依賴項

????????NDI SDK是用C++原生代碼進(jìn)行開發(fā)贮勃,想要在Android端使用C++的原生代碼,需要下載NDK和CMake兩個SDK工具包苏章,其中NDK工具集能夠允許Andoroid端調(diào)用C++代碼寂嘉,且通過JNI這類平臺庫,我們可以在MainActivity直接調(diào)用C++的函數(shù)枫绅,CMake是一款外部構(gòu)建工具泉孩,搭配“build.gradle”一起用,用來導(dǎo)入和關(guān)聯(lián)第三方C++庫并淋,具體操作方法如下:

1寓搬、在“Tools->SDK Manager->Android SDK->SDK tool”下,下載CMake和NDK工具县耽;

2句喷、如果在新建項目的時候,默認(rèn)勾選了“include C++ support”,會在項目文件的“/src/main/"目錄下多一個cpp的文件夾兔毙,cpp文件夾的根目錄有CMake文件的模板唾琼,同時關(guān)于C++程序的頭文件和編譯好的*.so數(shù)據(jù)庫文件,放到對應(yīng)include和jniLibs文件夾下澎剥,如下圖所示锡溯,這些文件夾也可以通過自建的方式添加到項目里;

圖1.C++關(guān)聯(lián)項目錄結(jié)構(gòu)

3、“CMake.txt”文件關(guān)聯(lián)本地庫和第三方C++庫的方式如下圖所示祭饭,其中“native-lib”為本地庫涌乳,本地庫的名稱和路徑在CMake文件內(nèi)指定,默認(rèn)首選路徑是cpp文件夾的根目錄甜癞,當(dāng)cpp的根目錄找不到“native-lib.cpp”文件時,再到include文件夾下找宛乃;ndi-lib是導(dǎo)入的第三方庫悠咱,文件名是“l(fā)ibndi.so”,此處NDI SDK針對不同版本的CPU設(shè)定有不同的“l(fā)ibndi.so”文件征炼,系統(tǒng)會根據(jù)實際手機的CPU去優(yōu)選最匹配的“l(fā)ibndi.so”文件析既,當(dāng)匹配上第三方庫之后,就能在include文件夾下谆奥,調(diào)用第三方庫的C++頭文件眼坏;

圖2.CMake.txt文件內(nèi)關(guān)聯(lián)庫

4、“native-lib.cpp”文件默認(rèn)在關(guān)聯(lián)C++項目的時候自動生成酸些,里面通過JNI接口的方式宰译,打通C++和JAVA的對接,如下圖所示魄懂,我在此處用C++規(guī)范了一些NDI的初始化沿侈、推流、拉流的函數(shù)市栗,然后通過JNI接口把對應(yīng)的函數(shù)和參數(shù)映射到JAVA程序缀拭,圖中舉例是NDI初始化的接口函數(shù),返回類型為“空”填帽,函數(shù)名為“initialNDI”蛛淋,在JAVA文件中對應(yīng)的調(diào)取路徑為“Java_com_example_ndkdemo”項目,“RecordService”文件下,這些命名方式都是在“RecordService.java”中引入“native-lib”關(guān)聯(lián)項和函數(shù)以后篡腌,在”native-lib.cpp“中自動生成的接口函數(shù)褐荷;

圖3.native-lib中對JNI的規(guī)范

????????對應(yīng)“RecordService.java”文件中,首先需要引入“native-lib.cpp”關(guān)聯(lián)項哀蘑,如下圖所示诚卸,然后通過自定義的方式創(chuàng)建接口文件,接口文件可以創(chuàng)建很多個绘迁,“native-lib.cpp”文件中合溺,也可以引用之前導(dǎo)入好的第三方庫文件的頭文件,只要是涉及到C++語法的缀台,都可以在“native-lib.cpp”文件中操作棠赛,并通過JNI接口轉(zhuǎn)成JAVA函數(shù),具體可以參照J(rèn)NI的相關(guān)教程;

圖4.native-lib關(guān)聯(lián)java文件
圖5.在java文件中創(chuàng)建關(guān)聯(lián)函數(shù)

5睛约、”build.gradle“為Android程序的構(gòu)建文件鼎俘,其中包括第三方JAVA庫的依賴項,還有CMake文件的關(guān)聯(lián)項目辩涝,如下圖所示贸伐,在cppFlags項中,”-frtti“希望Android程序支持RTTI怔揩,”-fexceptions“表示Android程序啟動對C++異常處理的功能捉邢,這兩項功能不填,也不影響最終的編譯商膊,只是為了有助于調(diào)試程序而打開伏伐;

圖6.build.gradle中關(guān)聯(lián)CMake
圖7.build.gradle中第三方庫依賴項

6、”AndroidManifest.xml“文件中規(guī)范了Android程序的主進(jìn)程”MainActivity“啟動入口晕拆、規(guī)范程序的權(quán)限以及注冊主進(jìn)程中運行的服務(wù)藐翎,如下圖所示,主進(jìn)程中注冊了”RecordService“服務(wù)实幕,該服務(wù)可以被實例化吝镣,并且服務(wù)可以以”mediaProjection“接口服務(wù)的方式運行于前臺服務(wù)(服務(wù)優(yōu)先級最高);

????????原先Android5.0之前昆庇,AndroidManifest.xml文件中赤惊,能夠規(guī)范Android程序的所有權(quán)限,自5.0以后凰锡,某些Android程序的權(quán)限未舟,如調(diào)取屏幕、攝像頭掂为、麥克風(fēng)等操作裕膀,均通過在Activity進(jìn)程中,動態(tài)授權(quán)的方式獲取勇哗,這樣做同時也是為了保障Android程序的健康安全昼扛,下圖中顯示AndroidManifest.xml中打開的權(quán)限主要為網(wǎng)絡(luò)訪問和前臺服務(wù)的權(quán)限;

圖8.AndroidManifest中規(guī)定服務(wù)類型
圖9.AndroidManifest中規(guī)范權(quán)限

2.2欲诺、NDI發(fā)送端實現(xiàn)方式

NDI發(fā)送端程序流程框圖如下圖所示:

圖10.NDI發(fā)送端流程框圖

1抄谐、在MainActivity主進(jìn)程建立時,開啟一個按鈕監(jiān)聽扰法,用于開啟錄屏服務(wù)(RecordService)并推送為前臺服務(wù)蛹含,同時綁定錄屏服務(wù)并返回一個錄屏服務(wù)的實例對象;

2塞颁、此處把bindService和startForegroundService兩種服務(wù)的開啟方式進(jìn)行了混用浦箱,混用后實現(xiàn)了Service服務(wù)與主線程的通信吸耿,同時把Service服務(wù)實例化,兩種服務(wù)方式的開啟并不會產(chǎn)生兩個單獨的錄屏服務(wù)酷窥,首先通過bindService綁定并連接上RecordService服務(wù)咽安,覆寫RecordService內(nèi)”onCreate“和”onBind“兩種方法,具體程序如下蓬推,綁定RecordService后使用“ServiceConnection”對服務(wù)進(jìn)行連接妆棒,連接前根據(jù)具體需求,可以申請一些動態(tài)權(quán)限沸伏,如存儲的讀寫募逞、手機狀態(tài)的讀取和錄制音頻等,連接成功后馋评,返回RecordService實力對象;

圖11.bindService的方法

????????在”RecordService“內(nèi)的”onCreate"重寫函數(shù)中刺啦,”getDisplayMetrics“為獲取手機顯示畫布留特,進(jìn)而得到手機顯示的長、寬玛瘸、dpi等參數(shù)蜕青;后臺線程”serviceThread“,用做后臺錄屏的子線程容器糊渊;“NSDServer”為網(wǎng)絡(luò)服務(wù)發(fā)現(xiàn)右核,為Android自帶的,用于在局域網(wǎng)內(nèi)網(wǎng)絡(luò)服務(wù)發(fā)現(xiàn)渺绒;initialNDI為初始化NDI的JNI接口程序贺喝。

圖12.RecordService中onCreate重寫

????????在”RecordService“內(nèi)的在“onBind”重寫函數(shù)中,主要為了在主進(jìn)程中連接上錄屏服務(wù)(RecordService)后宗兼,返回一個服務(wù)對象躏鱼,實現(xiàn)主進(jìn)程和服務(wù)之間的通信,如停止服務(wù)的操作殷绍。

圖13.RecordService中onBind重寫

3染苛、當(dāng)在MainActivity主進(jìn)程中按下按鈕以后,打開錄屏接口(MediaProjectionManager)并觸發(fā)“startForegroundService”主到,將RecordService服務(wù)開啟為前臺服務(wù)茶行,具體程序如下;

????????獲取MediaProjectionManager服務(wù)實例登钥,并調(diào)用錄屏權(quán)限“createScreenCaptureIntent”;

圖14. MediaProjectionManager服務(wù)實例化

????????通過"startActivityForResult",將錄屏權(quán)限(captureIntent)和固定參數(shù)(RECORD_REQUEST_CODE)傳入其中畔师,等待動態(tài)權(quán)限的申請結(jié)果;

圖15.startActivityForResult動態(tài)申請權(quán)限方法

????????等待動態(tài)錄屏權(quán)限申請通過牧牢,之后將通過成功后返回的參數(shù)傳遞給RecordService服務(wù)茉唉,并將RecordService開啟為前臺服務(wù)固蛾;


圖16.onActivityResult中等待動態(tài)結(jié)果返回并處理

4、之前在bindService的時候度陆,已經(jīng)生成并返回了RecordService服務(wù)的實例對象艾凯,因此“startForegroundService”開啟以后,直接在RecordService服務(wù)中懂傀,重寫“onStartCommand”和“onDestroy”兩個方法趾诗。

????????在”RecordService“內(nèi)的”onStartCommand"重寫函數(shù)中,創(chuàng)建RecordService前臺服務(wù)的通知欄和ID號(必須創(chuàng)建)蹬蚁,將動態(tài)申請錄屏服務(wù)時返回的參數(shù)獲取到恃泪,并依據(jù)這些創(chuàng)建“MeidaProjection”錄屏服務(wù)實例,并開始錄屏犀斋;

圖17.onStartCommand重寫方法

5贝乎、錄屏和NDI推流通過“startCapture”函數(shù)來實現(xiàn),首先通過"createVirtualDisplay"創(chuàng)建一塊虛擬畫布叽粹,傳入之前讀取的手機長览效、寬、dpi參數(shù)并通過“ImageReader”實例化對象虫几,將手機桌面讀取并放到虛擬畫布上锤灿;

圖18.createVirtualDisplay創(chuàng)建虛擬畫布

????????然后啟動之前在RecordService服務(wù)“onCreate”時就初始化的線程“serviceThread”,等待“createVirtualDisplay”中創(chuàng)建對應(yīng)尺寸的畫布辆脸,程序里等了1000ms但校,實際創(chuàng)建畫布不需要這么長;

????????最后通過子線程“backgroundHandler”中放入循環(huán)的“serviceThread”線程啡氢,每次循環(huán)后自動去調(diào)取回調(diào)函數(shù)ChildCallback,用于后臺錄屏數(shù)據(jù)實時推流NDI状囱;

圖19.startCapture函數(shù)實現(xiàn)方式

6、在“ChildCallback”回調(diào)函數(shù)中倘是,每次回調(diào)觸發(fā)以后浪箭,讀取最新手機錄屏圖像,讀取圖像以RGBA的方式進(jìn)行排布辨绊,每個像素點占4個byte奶栖,分別為RGBA,將圖像從左往右门坷、從上往下宣鄙,按照像素點的方式,以16進(jìn)制數(shù)據(jù)存入到byte數(shù)組中默蚌,得到的“b”數(shù)組是正向手機錄屏數(shù)據(jù)冻晤;

????????同時將這些像素點,以鏡像的方式重排绸吸,存入"mirrorByte"數(shù)組中鼻弧,與“b”數(shù)組一起设江,通過JNI接口推送給C++函數(shù),并一起推流攘轩,最終實現(xiàn)正向畫面和鏡像畫面同時出現(xiàn)在NDI網(wǎng)絡(luò)中叉存;

圖20.ChildCallback回調(diào)函數(shù)用法
圖21.通過鏡像方式重新排列數(shù)組

2.3、NSD(Network Service Discovery)服務(wù)的使用

????????為了使得發(fā)送的NDI流能夠被局域網(wǎng)里的其他設(shè)備發(fā)現(xiàn)度帮,需要在Android端打開Google原生的NSD服務(wù)歼捏,并且在Android端NDI目前不支持第三方的網(wǎng)絡(luò)發(fā)現(xiàn)服務(wù)(蘋果端使用的是Bonjour)。NSD是Andorid SDK內(nèi)部自帶的類庫笨篷,它的作用是為下一步的連接提供準(zhǔn)備瞳秽,如提供IP地址和端口號等,我們此次發(fā)送端率翅,作為NSD服務(wù)端發(fā)布到局域網(wǎng)中练俐,它定義了主機的名字、端口號冕臭,并進(jìn)行了注冊腺晾,為NSD客戶端的連接做準(zhǔn)備。

圖22.NDI SDK中說明對NSD的使用

????我在Android發(fā)送端程序里浴韭,建立了一個“NSDServer”的類,專門用于NSD服務(wù)端的注冊監(jiān)聽脯宿,具體步驟如下:

1念颈、設(shè)置注冊監(jiān)聽函數(shù),實例化監(jiān)聽服務(wù)器连霉,用于監(jiān)聽之后的注冊服務(wù)是否成功榴芳,如注冊失敗后的操作(onRegistrationFailed)、注冊成功后的操作(onServiceRegistered)跺撼、解除注冊失敗后的操作(onUnregistrationFailed)等等窟感;

圖23.NSD注冊監(jiān)聽服務(wù)

2、設(shè)置注冊NSD服務(wù)端函數(shù)歉井,設(shè)置服務(wù)端口號柿祈、服務(wù)端名稱、服務(wù)類型哩至,服務(wù)端的端口號是5960(NDI SDK文檔規(guī)定)躏嚎;

圖24.注冊NSD服務(wù)端

3、設(shè)置取消注冊函數(shù)菩貌,用于停止NSD服務(wù)端的操作卢佣;

圖25.取消NSD服務(wù)

4、NSD服務(wù)端狀態(tài)的監(jiān)聽接口箭阶,并設(shè)置實例化對象虚茶;

圖26.NSD服務(wù)注冊監(jiān)聽接口

5戈鲁、當(dāng)“NSDServer”類寫完以后,需要在“RecordService”服務(wù)中嘹叫,實例化該類婆殿,并調(diào)用"startNSDServer"接口,實現(xiàn)整個NSD服務(wù)端的初始化待笑、注冊及監(jiān)聽鸣皂;關(guān)于NSD客戶端的掃描、發(fā)現(xiàn)和解析NSD服務(wù)器暮蹂,主要應(yīng)用在NDI接收端寞缝,在此不做介紹。

圖27. “RecordService”中實現(xiàn)方式

2.4仰泻、NDI SDK中JNI接口的實現(xiàn)方式

????????在“RecordService”服務(wù)中荆陆,調(diào)用了兩個NDI的JNI接口函數(shù),分別為“initialNDI”和“publishNDI”集侯,在“RecordService”服務(wù)中以JAVA方式的寫法如下被啼,分別表示初始化NDI流和推送NDI留,這類函數(shù)的用法棠枉,跟“RecordService”服務(wù)中其他函數(shù)的使用方法一樣浓体。

圖28.“RecordService”服務(wù)中的JNI接口函數(shù)

? “nativie-lib.cpp”的C++文件中,對應(yīng)有initialNDI和publishNDI的C++函數(shù)實現(xiàn)方式辈讶,在了解C++函數(shù)前命浴,首先需要知道NDI SDK中規(guī)范的NDI流發(fā)送流程,具體步驟如下:

1贱除、初始化NDI相關(guān)庫(NDIlib_initialize)生闲,官方要求開始NDI之前一定要做初始化工作;

2月幌、創(chuàng)建NDI發(fā)送端的配置指針(NDIlib_send_create_t )碍讯,根據(jù)實際情況,設(shè)定NDI發(fā)送流的名字扯躺、組等信息捉兴;

3、依據(jù)創(chuàng)建好的NDI配置指針录语,實例化對應(yīng)的發(fā)送對象(NDIlib_send_instance_t)轴术,并返回一個發(fā)送對象的指針;

4钦无、把圖像數(shù)據(jù)動態(tài)分配給一個空間內(nèi)逗栽,并返回一個指針,如果圖像采用1920*1080的分辨率失暂,且使用BGRA的顏色空間彼宠,那么實際給每一幀圖像分配的內(nèi)存空間為1920*1080*4鳄虱,單位為Byte;

5凭峡、初始化NDI視頻幀的指針(NDIlib_video_frame_v2_t)拙已,設(shè)置NDI視頻幀對應(yīng)的分辨率、色彩空間摧冀、寬高倍踪、幀率等,可根據(jù)項目實際情況具體設(shè)置索昂;

6建车、將視頻幀的指針,放入到NDI發(fā)送的緩存里(NDIlib_send_send_video_v2)椒惨,NDI自動發(fā)送視頻數(shù)據(jù)缤至;

7、之后清空視頻幀里對應(yīng)的視頻數(shù)據(jù)康谆,重新放入新的數(shù)據(jù)并發(fā)送领斥,并進(jìn)入循環(huán);

8沃暗、發(fā)送音頻的原理跟發(fā)送視頻一樣月洛,需要指定音頻幀的指針(NDIlib_audio_frame_v3_t),分配空間孽锥,并放入發(fā)送音頻的數(shù)據(jù)(NDIlib_send_send_audio_v3)嚼黔;

????????在Android Studio中使用JNI接口具體通過“nativie-lib.cpp”實現(xiàn),在程序編譯之初忱叭,“nativie-lib.cpp”本地就運行了一遍C++程序隔崎,因此“nativie-lib.cpp”本地的全局參數(shù)和對象今艺,都可以直接被應(yīng)用到函數(shù)中韵丑,使用JNI接口發(fā)送NDI留的具體實現(xiàn)方式如下:

1、“nativie-lib.cpp”本地實例化兩個NDI發(fā)送端的配置指針(NDIlib_send_create_t?)虚缎、NDI視頻幀的指針(NDIlib_video_frame_v2_t)和發(fā)送對象(NDIlib_send_instance_t)撵彻,主要用作正常視頻和鏡像視頻的發(fā)送;

圖29.初始化NDI相關(guān)實例對象

2实牡、在“nativie-lib.cpp”的"initialNDI"函數(shù)中陌僵,初始化一些發(fā)送配置,如設(shè)定NDI流的名字创坞,色彩空間信息碗短;

圖?30.“nativie-lib.cpp”中初始化NDI

3、在"RecordService"服務(wù)中题涨,調(diào)用“initialNDI”的JNI接口后偎谁,實際跳轉(zhuǎn)運行如下总滩,初始化時,創(chuàng)建了兩個發(fā)送對象指針“p_send”和“p_send2”;

圖31.initialNDI的JNI接口函數(shù)

4巡雨、在“nativie-lib.cpp”的"publishNDI2"函數(shù)中闰渔,設(shè)定好發(fā)送視頻的分辨率,根據(jù)視頻數(shù)據(jù)的指針铐望,發(fā)送正常和鏡像兩個NDI流冈涧;

圖32. “nativie-lib.cpp”中發(fā)送NDI流

5、在"RecordService"服務(wù)中正蛙,調(diào)用“publishNDI”的JNI接口后督弓,實際跳轉(zhuǎn)運行如下,"RecordService"服務(wù)中跟畅,將已經(jīng)生成的正常咽筋、鏡像數(shù)據(jù)的數(shù)組發(fā)送給JNI接口,JNI接口里再將這些數(shù)組轉(zhuǎn)成jbyte指針徊件,就能供“publishNDI2”函數(shù)調(diào)用奸攻;

圖33.publishNDI接口函數(shù)

6、在"RecordService"服務(wù)中循環(huán)讀取最新桌面的錄屏圖像虱痕,并轉(zhuǎn)成byte數(shù)組睹耐,發(fā)送給“publishNDI”函數(shù)進(jìn)行推流。

三部翘、NDI SDK在使用中的分析

????NDI SDK雖然支持蘋果端和Android的開發(fā)應(yīng)用硝训,但在底層,套用的還是一套C++的庫文件新思,到手機端需要通過不同的接口轉(zhuǎn)換窖梁,因此在實際開發(fā)應(yīng)用中,還會遇到不少的瓶頸和疑惑夹囚,我把優(yōu)缺點進(jìn)行了總結(jié)和分析纵刘。

NDI SDK的優(yōu)點:

1、基于C++開發(fā)荸哟,對外只暴露一些接口調(diào)用函數(shù)假哎,可通過特定接口(JNI)實現(xiàn)跨平臺應(yīng)用的開發(fā),代碼統(tǒng)一鞍历,更新迭代方便舵抹;

2、NDI的收發(fā)對流進(jìn)行自適應(yīng)匹配劣砍,發(fā)送端不管是什么分辨率惧蛹、寬高比、幀率,在接收端都能收到并進(jìn)行匹配香嗓,NDI SDK中爵政,不需要對流的編解碼,做深入的處理陶缺;

3钾挟、NDI SDK代碼開源,有很好的收發(fā)流例子饱岸,低成本的特性掺出,使得國內(nèi)外開發(fā)應(yīng)用案例比較多。

NDI SDK的缺點:(主要針對在Android端的開發(fā))

1苫费、NDI內(nèi)部視頻流的編解碼不開放汤锨,NDI SDK里面只是把像素數(shù)據(jù)發(fā)送給NDI發(fā)送端,NDI 4的不支持H.264/265相關(guān)應(yīng)用設(shè)置百框,NDI 5支持闲礼,但有限制,并且調(diào)用SDK只能發(fā)送HX的流铐维;

2柬泽、NDI SDK中,不支持流的實施輸入和輸出嫁蛇,如Android端使用錄屏接口“mediaProjection”的流锨并,沒法送給NDI,只能需要通過截屏的方法睬棚,獲取像素信息后第煮,在發(fā)送給NDI接收,這樣效率比較低抑党,延遲大包警,NDI 5中還沒有給出很好的支持方法,只能依賴Android端“mediaProjection”的流的轉(zhuǎn)換底靠;

3害晦、Android端本身由于安全性考慮,要把本地的音頻流串流到NDI里面苛骨,需要改復(fù)雜的權(quán)限設(shè)置篱瞎,目前暫時只支持麥克風(fēng)的調(diào)用苟呐;

4痒芝、沒有對于高清、4K流的一些詳細(xì)規(guī)范牵素,比如說4K制作中最常見的HLG和BT2020的設(shè)置严衬,NDI為了降低應(yīng)用沒看,把很多涉及編解碼的東西都放到了后臺處理笆呆,這就使得我們在做一些專業(yè)視音頻項目開發(fā)的時候很痛苦请琳,得不到更好的支持粱挡;

四、總結(jié)

????此次應(yīng)用NDI SDK開發(fā)俄精,主要是想用于NDI在便攜式提詞器上的一些應(yīng)用询筏,比如說攝像出去外拍,只需要帶1太攝像機和Android平板竖慧,Android平板端為NDI接收嫌套,攝像手機端為NDI發(fā)送,通過無線的方式圾旨,把稿件信息直接串流到Android平板上踱讨,省去的復(fù)雜的提詞器系統(tǒng)搭建和設(shè)置過程;因此在程序設(shè)計時砍的,除了輸出NDI主畫面以外痹筛,還輸出了一個鏡像畫面,使用人員可以根據(jù)實際應(yīng)用廓鞠,使用主畫面或鏡像畫面帚稠。

????NDI SDK開發(fā)的時候是在3月份,當(dāng)時還只有NDI 4的支持床佳,很多NDI的工具原理還不清楚翁锡,只能在開發(fā)過程中一步步嘗試,開發(fā)出來的產(chǎn)品幀率也比較低夕土,今后基于NDI 5,尤其是NDI Bridge和H265編解碼方面馆衔,還要做更深入的研究,下圖為實際的NDI輸出效果怨绣。

圖34.軟件運行效果
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末角溃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子篮撑,更是在濱河造成了極大的恐慌减细,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赢笨,死亡現(xiàn)場離奇詭異未蝌,居然都是意外死亡,警方通過查閱死者的電腦和手機茧妒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門萧吠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人桐筏,你說我怎么就攤上這事纸型。” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵狰腌,是天一觀的道長除破。 經(jīng)常有香客問我,道長琼腔,這世上最難降的妖魔是什么瑰枫? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮丹莲,結(jié)果婚禮上躁垛,老公的妹妹穿的比我還像新娘。我一直安慰自己圾笨,他們只是感情好教馆,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著擂达,像睡著了一般土铺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上板鬓,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天悲敷,我揣著相機與錄音,去河邊找鬼俭令。 笑死后德,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抄腔。 我是一名探鬼主播瓢湃,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赫蛇!你這毒婦竟也來了绵患?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤悟耘,失蹤者是張志新(化名)和其女友劉穎落蝙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體暂幼,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡筏勒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了旺嬉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片管行。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鹰服,靈堂內(nèi)的尸體忽然破棺而出病瞳,到底是詐尸還是另有隱情,我是刑警寧澤悲酷,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布套菜,位于F島的核電站,受9級特大地震影響设易,放射性物質(zhì)發(fā)生泄漏逗柴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一顿肺、第九天 我趴在偏房一處隱蔽的房頂上張望戏溺。 院中可真熱鬧,春花似錦屠尊、人聲如沸旷祸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽托享。三九已至,卻和暖如春浸赫,著一層夾襖步出監(jiān)牢的瞬間闰围,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工既峡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留羡榴,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓运敢,卻偏偏與公主長得像校仑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子传惠,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容