web端遠(yuǎn)程控制iOS真機(jī) - Part1視頻流傳輸

目標(biāo)

實(shí)現(xiàn)web端遠(yuǎn)程展示和控制iOS真機(jī)

Part1 實(shí)時(shí)展示屏幕

通過(guò)簡(jiǎn)單調(diào)研盏檐,發(fā)現(xiàn)大家都在使用ios-minicap复斥,下來(lái)了看看。

ios-minicap通過(guò)使用私有接口開(kāi)啟ios視頻流疗疟,將視頻流編碼為jpg圖片署鸡,通過(guò)websocket發(fā)送到前端,前端實(shí)時(shí)展示圖片绊诲,達(dá)到實(shí)時(shí)展示界面的效果送粱。

實(shí)時(shí)展示圖片對(duì)流量有一定負(fù)擔(dān),這里考慮通過(guò)h264編碼的視頻流方式傳遞給前端實(shí)時(shí)展示驯镊。

目前還有對(duì)圖片做diff然后決定是否更新的方案葫督,但是在同樣的流量限制下竭鞍,fps是不如視頻流的, 就不適合播放視頻或游戲場(chǎng)景。

Web端播放視頻流

目前可選不多橄镜,廣泛使用基于Broadway這個(gè)h264解碼庫(kù).

這里選擇一個(gè)封裝了Broadway的npm庫(kù):

h264-live-player (https://github.com/131/h264-live-player)

只需要提供視頻流的websocket地址偎快,就可以打開(kāi)demo頁(yè)面,播放視頻了洽胶。略過(guò)晒夹。

iOS端生成視頻流

新建mac cmdline項(xiàng)目,參照minicap姊氓,首先開(kāi)啟iOS設(shè)備錄制的功能


-(void)EnableDALDevices{

    CMIOObjectPropertyAddress prop = {

        kCMIOHardwarePropertyAllowScreenCaptureDevices,

        kCMIOObjectPropertyScopeGlobal,

        kCMIOObjectPropertyElementMaster

    };

    UInt32allow =1;

    CMIOObjectSetPropertyData(kCMIOObjectSystemObject,

                              &prop,0,NULL,

                              sizeof(allow), &allow );

}

接下來(lái)我們需要找到連接的設(shè)備id

-(NSString*)getConnectedDeviceId{
    NSArray* devs = [AVCaptureDevice devicesWithMediaType:AVMediaTypeMuxed];
    NSString *deviceId;
    for(AVCaptureDevice* d in devs) {
        //如果通過(guò)命令行參數(shù)指定了連接的設(shè)備id丐怯,則只判斷這個(gè)設(shè)備id
        if(self.targetDeviceId){
            if( [self.targetDeviceId isEqualToString:d.uniqueID]){
                deviceId = self.targetDeviceId;
                NSLog(@"found connected device %@",d.localizedName);
                break;
            }
        }else if([d.modelID isEqualToString:@"iOS Device"]){
            deviceId = d.uniqueID;
            NSLog(@"found connected device %@",d.localizedName);
            break;
        }
    }
    return deviceId;
}

這里順便支持下命令行啟動(dòng)時(shí)連接指定設(shè)備。

在調(diào)用EnableDALDevices方法后翔横,立即調(diào)用getConnectedDeviceId方法并不會(huì)拿到想要的設(shè)備id读跷,有一定的延遲。

stackoverflow上有監(jiān)聽(tīng)設(shè)備連接的通知方法禾唁,但是試了下不work效览。這里偷懶就用個(gè)timer輪詢吧。

設(shè)備斷開(kāi)連接的檢測(cè)同樣可以用timer搞定荡短,但是要注意丐枉,一旦開(kāi)始了視頻連接,再次調(diào)用getConnectedDeviceId是可能拿到空值的掘托。

視頻流處理

偷懶找了個(gè)github項(xiàng)目瘦锹,項(xiàng)目將攝像頭采集的視頻流通過(guò)VideoToolbox庫(kù)轉(zhuǎn)換為h264視頻流。

稍微更改下VideoCapture中的代碼:

- (instancetype)initWithCaptureParam:(VCVideoCapturerParam *)param error:(NSError *__autoreleasing  _Nullable * _Nullable)error;
...
        // 通過(guò)傳入的device id闪盔,創(chuàng)建AVCaptureDevice
        AVCaptureDevice *mDevice = [AVCaptureDevice deviceWithUniqueID: param.deviceID];
        self.captureDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:mDevice error:&errorMessage];

 self.captureVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
        ...
      //web端解碼器是YpCbCr顏色編碼弯院,這里需要設(shè)置下。
        NSDictionary *videoSetting = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8Planar], kCVPixelBufferPixelFormatTypeKey,
              AVVideoScalingModeResizeAspect, (id)AVVideoScalingModeKey,nil];
        [self.captureVideoDataOutput setVideoSettings:videoSetting];
...

        //設(shè)置fps
        if(self.captureConnection.supportsVideoMinFrameDuration){
            self.captureConnection.videoMinFrameDuration = CMTimeMake(1, param.frameRate);
        }
...
}

編碼器VideoEncoder代碼:

- (instancetype)initWithParam:(VEVideoEncoderParam *)param
...
        //h264的profile泪掀,web端只支持Baseline
        profileRef = kVTProfileLevel_H264_Baseline_3_0;
...
}

搞定了視頻編碼抽兆,下面將數(shù)據(jù)傳輸給前端

視頻流傳輸

隨便找了個(gè)mac端的socket庫(kù) MBWebSocket
這庫(kù)默認(rèn)都按utf8字符發(fā)送,所以添加了個(gè)sendData方法族淮,發(fā)送data類型的數(shù)據(jù)辫红。

初始化之,端口由上層代碼傳入

    self.socket = [[MBWebSocketServer alloc] initWithPort:self.port delegate:self];

在編碼收到的回調(diào)中發(fā)送包

//got NAL unit from encoder
- (void)videoEncodeOutputDataCallback:(NSData *)data isKeyFrame:(BOOL)isKeyFrame
{
    [self.socket sendData:data];
}

另外由于web端的h264庫(kù)比較笨祝辣,需要預(yù)先知道播放視頻的寬高贴妻,我們需要在發(fā)送第一幀數(shù)據(jù)前發(fā)送編碼后的視頻寬高數(shù)據(jù),略過(guò)蝙斜。

命令行參數(shù)

命令行參數(shù)需要支持fps名惩、bitrate、resolution孕荠、指定設(shè)備id等設(shè)置娩鹉。
也可以通過(guò)websocket傳入視頻參數(shù)動(dòng)態(tài)更改攻谁。
詳略。

注意:更改分辨率寬高應(yīng)該設(shè)置為16的倍數(shù)弯予,否則系統(tǒng)會(huì)自動(dòng)優(yōu)化為16倍數(shù)戚宦。

Next

控制流

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锈嫩,隨后出現(xiàn)的幾起案子受楼,更是在濱河造成了極大的恐慌,老刑警劉巖呼寸,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件艳汽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡对雪,警方通過(guò)查閱死者的電腦和手機(jī)河狐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瑟捣,“玉大人甚牲,你說(shuō)我怎么就攤上這事〉粒” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵非驮,是天一觀的道長(zhǎng)交汤。 經(jīng)常有香客問(wèn)我,道長(zhǎng)劫笙,這世上最難降的妖魔是什么芙扎? 我笑而不...
    開(kāi)封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮填大,結(jié)果婚禮上戒洼,老公的妹妹穿的比我還像新娘。我一直安慰自己允华,他們只是感情好圈浇,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著靴寂,像睡著了一般磷蜀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上百炬,一...
    開(kāi)封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天褐隆,我揣著相機(jī)與錄音,去河邊找鬼剖踊。 笑死庶弃,一個(gè)胖子當(dāng)著我的面吹牛衫贬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播歇攻,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼固惯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了掉伏?” 一聲冷哼從身側(cè)響起缝呕,我...
    開(kāi)封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斧散,沒(méi)想到半個(gè)月后供常,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸡捐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年栈暇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箍镜。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡源祈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出色迂,到底是詐尸還是另有隱情香缺,我是刑警寧澤,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布歇僧,位于F島的核電站图张,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏诈悍。R本人自食惡果不足惜祸轮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望侥钳。 院中可真熱鬧适袜,春花似錦、人聲如沸舷夺。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)给猾。三九已至躏啰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間耙册,已是汗流浹背给僵。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人帝际。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓蔓同,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蹲诀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子斑粱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

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

  • 生意這件事從來(lái)都不是簡(jiǎn)單的,道路上遇到各式各樣的問(wèn)題脯爪,而你直接面對(duì)客戶就會(huì)有更多的問(wèn)題產(chǎn)生则北。這個(gè)時(shí)候如何選擇變得尤...
    zhangxi2370閱讀 203評(píng)論 0 0
  • 以管理員身份運(yùn)行cmd 然后再執(zhí)行pip的更新命令
    偶然路過(guò)的靚仔_胡陽(yáng)閱讀 191評(píng)論 0 1
  • 海邊的石頭 圍著海島一圈有很多這樣的石頭 大大小小形狀各異 行人或匆匆而過(guò)或停留嬉戲 我們的聲音就像海水一樣 沖刷...
    珠海艷陽(yáng)天閱讀 237評(píng)論 0 3
  • 沒(méi)有調(diào)鬧鐘,沒(méi)有叫床服務(wù)痕慢,感覺(jué)潛意識(shí)里在叫我起床尚揣,因?yàn)槲乙銉鹤尤ヌ琛N覇?wèn)他爸幾點(diǎn)啦掖举,八點(diǎn)快骗,這時(shí)東嶼也醒...
    楊夢(mèng)旋閱讀 190評(píng)論 0 1
  • 本周跑步一次,當(dāng)天是下夜班塔次,回來(lái)沒(méi)有休息好方篮,中間被吵醒,身體還沒(méi)有恢復(fù)狀態(tài)励负,晚上就出去跑步了藕溅。難得有時(shí)間去跑步,暢...
    奔跑的魚(yú)7閱讀 369評(píng)論 3 3