web端远程控制iOS真机 - Part1视频流传输

目标

实现web端远程展示和控制iOS真机

Part1 实时展示屏幕

通过简单调研,发现大家都在使用ios-minicap,下来了看看。

ios-minicap通过使用私有接口开启ios视频流,将视频流编码为jpg图片,通过websocket发送到前端,前端实时展示图片,达到实时展示界面的效果。

实时展示图片对流量有一定负担,这里考虑通过h264编码的视频流方式传递给前端实时展示。

目前还有对图片做diff然后决定是否更新的方案,但是在同样的流量限制下,fps是不如视频流的, 就不适合播放视频或游戏场景。

Web端播放视频流

目前可选不多,广泛使用基于Broadway这个h264解码库.

这里选择一个封装了Broadway的npm库:

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

只需要提供视频流的websocket地址,就可以打开demo页面,播放视频了。略过。

iOS端生成视频流

新建mac cmdline项目,参照minicap,首先开启iOS设备录制的功能


-(void)EnableDALDevices{

    CMIOObjectPropertyAddress prop = {

        kCMIOHardwarePropertyAllowScreenCaptureDevices,

        kCMIOObjectPropertyScopeGlobal,

        kCMIOObjectPropertyElementMaster

    };

    UInt32allow =1;

    CMIOObjectSetPropertyData(kCMIOObjectSystemObject,

                              &prop,0,NULL,

                              sizeof(allow), &allow );

}

接下来我们需要找到连接的设备id

-(NSString*)getConnectedDeviceId{
    NSArray* devs = [AVCaptureDevice devicesWithMediaType:AVMediaTypeMuxed];
    NSString *deviceId;
    for(AVCaptureDevice* d in devs) {
        //如果通过命令行参数指定了连接的设备id,则只判断这个设备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;
}

这里顺便支持下命令行启动时连接指定设备。

在调用EnableDALDevices方法后,立即调用getConnectedDeviceId方法并不会拿到想要的设备id,有一定的延迟。

stackoverflow上有监听设备连接的通知方法,但是试了下不work。这里偷懒就用个timer轮询吧。

设备断开连接的检测同样可以用timer搞定,但是要注意,一旦开始了视频连接,再次调用getConnectedDeviceId是可能拿到空值的。

视频流处理

偷懒找了个github项目,项目将摄像头采集的视频流通过VideoToolbox库转换为h264视频流。

稍微更改下VideoCapture中的代码:

- (instancetype)initWithCaptureParam:(VCVideoCapturerParam *)param error:(NSError *__autoreleasing  _Nullable * _Nullable)error;
...
        // 通过传入的device id,创建AVCaptureDevice
        AVCaptureDevice *mDevice = [AVCaptureDevice deviceWithUniqueID: param.deviceID];
        self.captureDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:mDevice error:&errorMessage];

 self.captureVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
        ...
      //web端解码器是YpCbCr颜色编码,这里需要设置下。
        NSDictionary *videoSetting = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8Planar], kCVPixelBufferPixelFormatTypeKey,
              AVVideoScalingModeResizeAspect, (id)AVVideoScalingModeKey,nil];
        [self.captureVideoDataOutput setVideoSettings:videoSetting];
...

        //设置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;
...
}

搞定了视频编码,下面将数据传输给前端

视频流传输

随便找了个mac端的socket库 MBWebSocket
这库默认都按utf8字符发送,所以添加了个sendData方法,发送data类型的数据。

初始化之,端口由上层代码传入

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

在编码收到的回调中发送包

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

另外由于web端的h264库比较笨,需要预先知道播放视频的宽高,我们需要在发送第一帧数据前发送编码后的视频宽高数据,略过。

命令行参数

命令行参数需要支持fps、bitrate、resolution、指定设备id等设置。
也可以通过websocket传入视频参数动态更改。
详略。

注意:更改分辨率宽高应该设置为16的倍数,否则系统会自动优化为16倍数。

Next

控制流

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 生意这件事从来都不是简单的,道路上遇到各式各样的问题,而你直接面对客户就会有更多的问题产生。这个时候如何选择变得尤...
    zhangxi2370阅读 207评论 0 0
  • 以管理员身份运行cmd 然后再执行pip的更新命令
    偶然路过的靓仔_胡阳阅读 195评论 0 1
  • 海边的石头 围着海岛一圈有很多这样的石头 大大小小形状各异 行人或匆匆而过或停留嬉戏 我们的声音就像海水一样 冲刷...
    珠海艳阳天阅读 258评论 0 3
  • 没有调闹钟,没有叫床服务,感觉潜意识里在叫我起床,因为我要陪儿子去跳舞。我问他爸几点啦,八点,这时东屿也醒...
    杨梦旋阅读 206评论 0 1
  • 本周跑步一次,当天是下夜班,回来没有休息好,中间被吵醒,身体还没有恢复状态,晚上就出去跑步了。难得有时间去跑步,畅...
    奔跑的鱼7阅读 390评论 3 3