iOS

# 视频管理

Juphoon 视频能力平台支持跨平台的一对一、多对多的通话模式的高清音视频通话,Juphoon RTC SDK 供业务灵活集成应用,实现视频管理能力。

# 1. 发送本地视频流

房间内的成员可通过调用 enableUploadVideoStream (opens new window) 方法来开启关闭发送本地视频流。

/**
 * 开启/关闭发送本地视频流
 *
 * - 调用该方法可开启或关闭发送本地视频流。开启后,频道成员将可以看见本端视频画面;关闭后,频道成员将看不见本端视频画面
 * - 频道中调用此方法不影响接收远端视频
 * - 初始化 JRTCRoom 时,默认发送本地视频流。若要加入频道时,让频道内其他成员看见本端视频画面,建议在调用 {@link #join join} 加入频道前设置
 * - 该方法在频道内和频道外均可调用,且在离开频道后该设置仍然有效。也就是说这一次设置了关闭发送本地视频流,那么在下一次加入频道时默认会关闭发送本地视频流
 * - 会议中也可调用此方法开启或关闭发送本地视频流,服务器会更新状态并同步给其他频道成员,即频道中所有成员都会收到 {@link JRTCRoomCallback#onParticipantUpdate onParticipantUpdate} 回调
 *
 * @param enable 是否发送本地视频流
 * - true: 开启,即发送本地视频流
 * - false: 关闭,即不发送本地视频流
 * @return 接口调用结果
 * - true: 接口调用成功
 *  - 在调用此方法时,用户不在频道中,不会收到回调
 *  - 在调用此方法时,用户在频道中,会收到 {@link JRTCRoomCallback#onRoomPropertyChange onRoomPropertyChange} 回调
 * - false: 接口调用异常
 */
public abstract boolean enableUploadVideoStream(boolean enable);
  1. 在多方通话中,enableUploadVideoStream (opens new window) 的作用是设置“是否上传视频流数据。调用该方法可开启或关闭发送本地视频流。开启后,房间成员将可以看见本端视频画面;关闭后,房间成员将看不见本端视频画面。房间中调用此方法不影响接收远端音频。
  2. 初始化 JRTCRoom 时,默认发送本地视频流。若要加入房间时,让房间内其他成员看见本端视频画面,建议在调用 join (opens new window) 加入房间前设置。房间中调用此方法不影响接收远端视频。
  3. 房间中也可调用此方法开启或关闭发送本地视频流,服务器会更新状态并同步给其他房间成员,房间中的其他成员会收到该成员“是否上传音频“的状态变化回调 onParticipantUpdate (opens new window)
  4. 该方法在房间内和房间外均可调用,且在离开房间该设置仍然有效。也就是说这一次设置了关闭发送本地视频流,那么在下一次加入房间时默认会关闭发送本地视频流。

此外,调用该方法发送本地视频流数据还要依赖摄像头是否已经打开。

/**
 * 成员属性更新回调
 *
 * 当房间中有成员的属性发生变化时,房间中的其他成员会收到此回调,例如音频上传状态、视频上传状态、网络状态等发生变化。
 * @param participant  JRTCRoomParticipant 成员对象
 * @param changeParam  {@link JRTCRoomParticipant.ChangeParam} 更新标识类对象
 * @param room 当前 JRTCRoom 对象
 */
void onParticipantUpdate(JRTCRoomParticipant participant, JRTCRoomParticipant.ChangeParam changeParam, JRTCRoom room);

示例代码:

// 关闭视频流发送
room.enableUploadVideoStream(false);
// 开启视频流发送
room.enableUploadVideoStream(true);
// 通话中成员属性更新回调
public void onParticipantUpdate(JRTCRoomParticipant participant, JRTCRoomParticipant.ChangeParam changeParam, JRTCRoom room) {
    if(participant.video){
        if(participant.isVideo()){
            //该成员视频流打开
        } else{
            //该成员视频流关闭
        }
    }
};

# 2. 订阅/取消订阅视频流

在房间中可以订阅其他成员不同分辨率的视频流,这个参数结合 SVC 来使用可以实现通话中切换设置的分辨率;订阅视频流 requestVideo (opens new window) ,取消订阅视频流 unRequestVideo (opens new window)

/**
  * 订阅频道中其他用户的视频流
  *
  * @param participant  JRTCRoomParticipant 成员对象
  * @param videoSize    视频请求的尺寸,详见 {@link JRTCVideoSize}
  * @return 接口调用结果
  * - true: 接口调用成功,会收到 {@link JRTCRoomCallback#onParticipantUpdate onParticipantUpdate} 回调
  * - false: 接口调用异常
  */
public abstract boolean requestVideo(JRTCRoomParticipant participant, JRTCVideoSize videoSize);

/**
  * 取消订阅频道中其他用户的视频流
  *
  * @param participant  JRTCRoomParticipant 频道中其他成员对象
  * @return 调用是否正常
  * - true: 正常执行调用流程,会收到 {@link JRTCRoomCallback#onParticipantUpdate onParticipantUpdate} 回调
  * - false: 调用失败,不会收到回调通知
  */
public abstract boolean unRequestVideo(JRTCRoomParticipant participant);

示例代码:

public void onParticipantJoin(JRTCRoomParticipant participant, JRTCRoom room) {
	// 使用 JRTCVideoSize 订阅视频流
	JRTCVideoSize size = new JRTCVideoSize();
	size.setWidth(720);
	size.setHeight(1080);
	room.requestVideo(participant, size);
    //...渲染视频
}

public void onParticipantLeft(JRTCRoomParticipant participant, JRTCRoom room) {
    //取消订阅该成员视频流
    room.unRequestVideo(participant);
    //...停止渲染视频
}

# 3. SVC 设置说明

根据实际订阅需求和网络状况动态调整视频发送分辨率是 JSM 房间的特性之一,SVC 可用于设置房间视频的每一层编码分辨率。该参数在房间创建时设置,且全局统一。

具体使用详见 SVC 说明 (opens new window)

可在加入房间时,通过加入房间参数 JRTCRoomJoinParam (opens new window)setSvcResolution (opens new window) 属性进行设置,房间全局属性,只有第一个加入房间用户设置有效。

/**
 * svc分辨率,默认为 "1 180 250 360 600 720 1400"
 *
 * 用于自定义分层参数和码率
 *
 * 格式:
 * 高度公约数 第一层高倍数 第一层码率 第二层高倍数 第二层码率 第三层高倍数 第三层码率 第四层高倍数 第四层码率 <br>
 * 说明 <br>
 * 1)默认宽高比16:9,即 @ref  wholeRatio <br>
 * 2)编码宽高最后被裁成16整除 <br>
 * 例如 "1 180 250 360 600 720 1400" <br>
 * 第一层 分辨率 宽320(180*1/9*16)高 180(180*1); 码率250kbps <br>
 * 第二层 分辨率 宽640(360*1/9*16)高 360(360*1); 码率600kbps <br>
 * 第三层 分辨率 宽1280(720*1/9*16)高 720(720*1); 码率1400kbps <br>
 * 此情况下只有三层,若需要四层,则需补充为 "1 180 250 360 600 720 1400 1080 1600" <br>
 * 第四层 分辨率 宽1920(1080*1/9*16)高 1080(1080*1); 码率1600kbps <br>
 */
public void setSvcResolution(String svcResolution);

示例代码:

JRTCRoomJoinParam param = new JRTCRoomJoinParam();
// 设置svc参数
param.setSvcResolution("1 180 250 360 600 720 1400 1080 1600");
// 加入房间
room.join("10086", param);            

# 4. 设置本地视频宽高比

在房间内设置本地房间宽高比,会影响视频画面宽高比,用于适配不同屏幕的显示需求,需在进入房间后调用。

/**
 * 设置本端视频宽高比
 *
 * 将自己的视频采集根据宽高比裁剪后进行发送,通话中其他成员收到的画面将是裁剪后的比例。<br>
 * 该方法不影响其他成员的画面在本端的显示比例,也不影响其他成员相互之间的画面显示比例。<br>
 * 必须 ***加入频道后*** 设置才能生效,即收到 {@link JRTCRoomCallback#onJoin onJoin} 回调后设置才生效。
 * @param ratio 视频宽高比
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
public abstract boolean setRatio(float ratio);

示例代码:

void onJoin(boolean result, @ReasonCode int reason, String roomId, JRTCRoom room){
    if (result) {
        // 注:在通话建立后调用才能生效,本地宽高比9/16
        room.setRatio(0.5625f);
    }
}

# 5. 设置视频清晰度

如果觉得设置 SVC 不好理解,可以直接调用 setVideoDefinition (opens new window) 来设置通话视频清晰度(一组已经定义的 SVC 和帧率),VideoDefinition (opens new window) 详见 API 文档。

/**
 * 设置房间视频清晰度,主要通过修改 {@link #setSvcResolution(String) svcResolution} 参数和 {@link #setMaxFrameRate(int) maxFrameRate} 参数调整清晰度,
 * 默认为 {@link JRTCRoom#DEFINITION_CUSTOM DEFINITION_CUSTOM}
 */
public void setVideoDefinition(@VideoDefinition int videoDefinition);

示例代码:

JRTCRoomJoinParam param = new JRTCRoomJoinParam();
// 设置通话视频清晰为流畅模式,低帧率
param.setVideoDefinition(JRTCRoom.DEFINITION_FLUENCY_FRAME_LOW);
// 加入房间
room.join("10086", param);  

# 6. 视频渲染管理

# 渲染视频画面

查看章节4.3.5 和 4.3.8

# 停止视频渲染

查看章节4.3.11

# 视频渲染回调

调用视频渲染接口后主要关注两个回调接口 onRenderReceived (opens new window)onRenderStart (opens new window)

使用场景举例:为了提升交互体验,可以在调用渲染接口后,UI 界面先显示 "视频加载中" 字样,等收到渲染开始接口时,再显示视频画面。

/**
 * 收到第一帧数据回调
 *
 * @param canvas 渲染对象
 * @param ratio  宽高比
 */
void onRenderReceived(JRTCMediaDeviceVideoCanvas canvas, double ratio);

/**
 * 渲染开始回调
 *
 * @param canvas 视图渲染对象
 * @param ratio  宽高比
 */
void onRenderStart(JRTCMediaDeviceVideoCanvas canvas, double ratio);

# 7. 视频截图

视频业务存在对当前通话截图的业务操作,以便于记录用户的操作行为;详见 snapshotWithStreamId (opens new window)

/**
 * 截图
 *
 * @param streamId  要截图的视频流ID
 * @param path      要存放截图的文件路径
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
public abstract boolean snapshotWithStreamId(String streamId, String path);

结果通过实现 JRTCMediaDeviceCallback (opens new window)onSnapshotComplete (opens new window) 接口上报

/**
 * 截图完成回调
 *
 * @param file   截图路径
 * @param width  图片像素宽
 * @param height 图片像素高
 */
void onSnapshotComplete(String file, int width, int height);

示例代码:

// 截取指定 视频流ID的帧图片并且保存到指定路径
// 视频流,可以是本地视频流、对端视频流或者屏幕共享视频流
mediaDevice.snapshotWithStreamId("user_renderId", "file_save_path");
// 截图完成回调
public void onSnapshotComplete(String file, int width, int height) {
    //截图完成,可以从文件路径获取截图文件进行后续操作 
}

# 8. 视频采集回调

当打开本端摄像头视频预览或者打开本地屏幕采集时,通过实现 JRTCMediaDeviceCallback (opens new window)onVideoCaptureDidStart (opens new window) 接口能收到采集开始通知

/**
 * 视频采集开始回调
 *
 * @param streamId 视频流ID
 * @param ratio    宽高比
 */
void onVideoCaptureDidStart(String streamId, double ratio);

# 9. 视频异常回调

通过实现 JRTCMediaDeviceCallback (opens new window)onVideoError (opens new window) 接口来监听视频异常、采集异常、渲染错误等事件,具体原因查看参数 error 描述。

/**
 * 视频异常,渲染错误,包括摄像头采集错误回调
 *
 * @param error 异常信息
 */
void onVideoError(String error);

# 10. 自定义视频数据

如果在房间内,用户不想用默认的摄像头视频数据,可以通过以下接口自定义注入视频数据;

/**
 * 开启视频文件作为视频输入源
 *
 * @note 文件和摄像头作为视频输入源只能存在一种,如果当前摄像头已开启的话会关闭摄像头
 * @return 接口调用结果
 * - true: 接口调用成功
 *  - 若调用此方法时文件视频源已开启,则不会收到回调
 *  - 若调用此方法时文件视频源还未开启,则会收到 {@link JRTCMediaDeviceCallback#onCameraUpdate onCameraUpdate} 回调
 * - false: 接口调用异常,不会收到回调
 */
public abstract boolean startVideoFile();

/**
 * 关闭视频文件作为视频输入源
 * @return 接口调用结果
 * - true: 接口调用成功
 *  - 若调用此方法时文件视频源已关闭,不会收到回调
 *  - 若调用此方法时文件视频源未关闭,则会收到 {@link JRTCMediaDeviceCallback#onCameraUpdate onCameraUpdate} 回调
 * - false: 接口调用异常
 */
public abstract boolean stopVideoFile();

/**
 * 逐帧采集视频画面
 * <p>
 * 当为 H264 格式时
 * 1. 如果是关键帧需要将 0x67 0x68 0x41 的数据作为一帧传入
 * 2. 关键帧要以固定间隔传入,例如5秒,否则一开始可能有几秒对端无法显示视频
 *
 * @param data     画面二进制数据
 * @param format   视频像素格式
 * @param width    宽
 * @param height   高
 * @param angle    90 的倍数
 * @param mirror   0 不镜像,1进行左右镜像
 * @param keyFrame 是否为关键帧,针对 format 为 H264
 */
public abstract void setVideoFileFrame(byte[] data, @VideoPixelFormat int format, int width, int height, int angle, int mirror, boolean keyFrame);

# 11. 视频帧回调

目前只支持渲染视频帧回调,即需要渲染某个成员视频或者渲染屏幕共享、本地视频后可以收到视频帧回调,

接口如下 setVideoFrameCallBack (opens new window)

/**
 * 设置视频帧回调
 *
 * @param frameCallback 回调对象
 */
public void setVideoFrameCallBack(VideoFrameCallback frameCallback);

public interface VideoFrameCallback {
    /**
     * 视频帧回调接口
     *
     * @param angle  帧图像旋转角度
     * @param mirror 帧图像是否镜像
     * @param width  帧图像宽度
     * @param height 帧图像高度
     * @param data   I420格式帧数据
     */
    void onFrame(int angle, boolean mirror, int width, int height, ByteBuffer data);
}

示例代码:

//开始本地视频渲染
JRTCMediaDeviceVideoCanvas canvas = mediaDevice.startCameraVideo(JRTCMediaDevice.RENDER_FULL_CONTENT);
//设置视频数据回调
canvas.setVideoFrameCallBack(new VideoFrameCallback() {
     void onFrame(int angle, boolean mirror, int width, int height, ByteBuffer data) {
         //视频数据
     }
});