视频直播

更新时间:2023-05-22 06:38:31下载pdf

涂鸦 IPC SDK iOS 版提供智能摄像机的实时视频播放、设备存储卡录像播放、对当前正在播放的视频截图、录制视频, 与摄像机实时通话等基础能力。此外,还提供视频帧解码后的 YUV 数据,您可以对视频数据进行二次处理。

在创建 TuyaSmartCameraType 实例对象后,就可以开始播放实时视频了。视频数据的传输和命令交互基于 P2P 通道实现。

P2P 连接

在开始播放视频之前,需要先连接 P2P 通道。P2P 的连接状态需要开发者自己维护,IPC SDK 只负责下发命令和接收摄像机响应结果。

接口说明

开始连接 P2P 通道,参数可以指定优先选择的连接模式,通过局域网连接或者通过外网连接,如果指定局域网连接优先,但是 App 和设备没有在同一个局域网内建立 TCP 连接,或者设备不支持局域网连接优先,SDK 会自动使用外网连接模式。

- (void)connectWithMode:(TuyaSmartCameraConnectMode)mode;

参数说明

参数 说明
mode 优先使用的连接模式

TuyaSmartCameraConnectMode

枚举值 说明
TuyaSmartCameraConnectAuto 自动选择
TuyaSmartCameraConnectFromInternet 外网连接优先
TuyaSmartCameraConnectFromLocal 局域网连接优先

接口说明

断开 P2P 通道

- (void)disConnect;

代理回调

P2P 通道成功连接

- (void)cameraDidConnected:(id<TuyaSmartCameraType>)camera;

P2P 通道已断开,被动断开时才会调用,如网络环境比较差,或者设备主动断开连接

- (void)cameraDisconnected:(id<TuyaSmartCameraType>)camera;

connect 方法可能会阻塞线程,建议在子线程调用。

实时视频播放

P2P 通道连接成功以后,就可以开始播放实时视频了。

接口说明

开始播放实时视频

- (void)startPreview;

开始播放实时视频,并指定清晰度,P2P 1.0 设备不支持

- (void)startPreviewWithDefinition:(TuyaSmartCameraDefinition)definition;

停止播放实时视频

- (void)stopPreview;

获取视频渲染视图

- (UIView<TuyaSmartVideoViewType> *)videoView;

代理回调

视频直播已经成功开始播放

- (void)cameraDidBeginPreview:(id<TuyaSmartCameraType>)camera;

视频直播已经成功停止播放

- (void)cameraDidStopPreview:(id<TuyaSmartCameraType>)camera;

视频渲染

视频成功播放后,IPC SDK 收到视频流将会自动渲染,开发者可以通过 camera 对象的 - (UIView<TuyaSmartVideoViewType> *)videoView 方法来获取渲染视图,将其添加到屏幕上,并设置布局属性。

协议说明

协议名 说明
TuyaSmartVideoViewType 视频渲染器协议,根据摄像机实现方案不同,视频渲染的具体实现也有不同

接口说明

图像缩放属性。默认是 NO,如果视图的宽高比和视频图像的宽高比不一样,则会在图像的上下或者左右两侧留有黑边。设置为YES,图像会拉伸铺满整个视图,可能会造成图像变形。

@property (nonatomic, assign) BOOL scaleToFill;

设置图像缩放比例

- (void)tuya_setScaled:(float)scaled;

设置图像偏移量

- (void)tuya_setOffset:(CGPoint)offset;

清除当前的图像和缓存的视频帧

- (void)tuya_clear;

对当前渲染的图像截图

- (UIImage *)screenshot;

TuyaSmartCameraType 对象还提供了一个 autoRender 属性,默认是 YES,IPC SDK 会自动渲染视频图像。如果开发者不希望 SDK 自动渲染视频,可将此属性设置为 NO,然后可以从代理方法中获取到每一帧视频的 YUV 数据,并自主开发视频渲染,详细的接口在裸流数据章节中介绍。

全屏播放

IPC SDK 并不提供全屏播放的能力,全屏播放只需要修改视频渲染视图的布局即可,若需要视频图像铺满视图,可以将scaleToFill属性设置为 YES,但是此时图像可能会被拉伸变形。全屏模式时,横竖屏的旋转,布局的变化都需要开发者自行维护。

流程图

视频直播

错误回调

摄像机操作的所有错误反馈都将通过代理方法回调。

接口说明

摄像机操作失败回调

- (void)camera:(id<TuyaSmartCameraType>)camera didOccurredErrorAtStep:(TYCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode;

参数说明

参数 说明
camera 发生错误的摄像机对象
errStepCode 发生错误的操作
errorCode 错误码,标示失败的原因

TYCameraErrorCode 枚举

枚举值 说明
TY_ERROR_NONE
TY_ERROR_CONNECT_FAILED P2P 连接失败
TY_ERROR_START_PREVIEW_FAILED 实时视频播放失败
TY_ERROR_START_PLAYBACK_FAILED 存储卡视频播放失败
TY_ERROR_PAUSE_PLAYBACK_FAILED 暂停存储卡视频播放失败
TY_ERROR_RESUME_PLAYBACK_FAILED 恢复存储卡视频播放失败
TY_ERROR_ENABLE_MUTE_FAILED 视频声音开关失败
TY_ERROR_START_TALK_FAILED 开启对讲失败
TY_ERROR_RECORD_FAILED 视频录制失败
TY_ERROR_ENABLE_HD_FAILED 设置视频清晰度失败
TY_ERROR_GET_HD_FAILED 获取视频清晰度失败
TY_ERROR_QUERY_RECORD_DAY_FAILED 存储卡视频回放日期查询失败
TY_ERROR_QUERY_TIMESLICE_FAILED 存储卡视频片段查询失败

errorCode的含义可以参考后面的错误码章节。

示例代码

ObjC

#define kTuyaSmartIPCConfigAPI @"tuya.m.ipc.config.get"
#define kTuyaSmartIPCConfigAPIVersion @"2.0"

- (void)startStream {
	if (self.connected) {
		[self.camera startPreview];
		return;
	}
	id p2pType = [self.deviceModel.skills objectForKey:@"p2pType"];
	[[TuyaSmartRequest new] requestWithApiName:kTuyaSmartIPCConfigAPI postData:@{@"devId": self.devId} version:kTuyaSmartIPCConfigAPIVersion success:^(id result) {
		dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
			TuyaSmartCameraConfig *config = [TuyaSmartCameraFactory ipcConfigWithUid:[TuyaSmartUser sharedInstance].uid localKey:self.deviceModel.localKey configData:result];
			self.camera = [TuyaSmartCameraFactory cameraWithP2PType:p2pType config:config delegate:self];
			[self.camera connect];
		});
	} failure:^(NSError *error) {
				// 获取配置信息失败
	}];
}

#pragma mark - TuyaSmartCameraDelegate

- (void)cameraDidConnected:(id<TuyaSmartCameraType>)camera {
	self.connected = YES;
	// 需要 P2P 连接成功后再开始预览
		[camera startPreview];
}

- (void)cameraDisconnected:(id<TuyaSmartCameraType>)camera {
	// P2P 连接被动断开,一般为网络波动导致
	self.connected = NO;
	self.previewing = NO;
}

- (void)cameraDidBeginPreview:(id<TuyaSmartCameraType>)camera {
		// 实时视频开始播放
	self.previewing = YES;
	// 将视频渲染视图添加到屏幕上
		[self.view addSubview:camera.videoView];
}

- (void)cameraDidStopPreview:(id<TuyaSmartCameraType>)camera {
		// 实时视频停止播放
	self.previewing = NO;
}

// 错误回调
- (void)camera:(id<TuyaSmartCameraType>)camera didOccurredErrorAtStep:(TYCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode {
		if (errStepCode == TY_ERROR_CONNECT_FAILED) {
		// P2P 连接失败
		self.connected = NO;
	}
	else if (errStepCode == TY_ERROR_START_PREVIEW_FAILED) {
		// 实时视频播放失败
		self.previewing = NO;
	}
}

Swift

func startStream() {
	if self.isConnected {
		self.camera.startPreview()
		return
	}
	let p2pType = self.deviceModel.skills["p2pType"]!
	TuyaSmartRequest().request(withApiName: kTuyaSmartIPCConfigAPI, postData: ["devId": self.devId], version: kTuyaSmartIPCConfigAPIVersion, success: { result in
		guard let responder = result as? [AnyHashable:Any] else {
			return;
		}
		DispatchQueue.global().async {
			let config = TuyaSmartCameraFactory.ipcConfig(withUid: TuyaSmartUser.sharedInstance().uid, localKey: self.deviceModel.localKey, configData: responder)
			self.camera = TuyaSmartCameraFactory.camera(withP2PType: p2pType, config: config, delegate: self)
			self.camera.connect()
		}
	}) { _ in
		// 获取配置信息失败
	}
}

func cameraDidConnected(_ camera: TuyaSmartCameraType!) {
	self.isConnected = true
	// 需要 P2P 连接成功后再开始预览
	camera.startPreview()
}

func cameraDisconnected(_ camera: TuyaSmartCameraType!) {
	// P2P 连接被动断开,一般为网络波动导致
	self.isConnected = false
	self.isPreviewing = false
}

func cameraDidBeginPreview(_ camera: TuyaSmartCameraType!) {
	// 实时视频开始播放
	self.isPreviewing = true;
	// 将视频渲染视图添加到屏幕上
	self.view.addSubview(camera.videoView())
}

func cameraDidStopPreview(_ camera: TuyaSmartCameraType!) {
	// 实时视频停止播放
	self.isPreviewing = false
}

func camera(_ camera: TuyaSmartCameraType!, didOccurredErrorAtStep errStepCode: TYCameraErrorCode, specificErrorCode errorCode: Int) {
	if errStepCode == TY_ERROR_CONNECT_FAILED  {
		// P2P 连接失败
		self.isConnected = false
	}else if errStepCode == TY_ERROR_START_PREVIEW_FAILED {
		// 实时视频播放失败
		self.isPreviewing = false
	}
}

App 进入后台的时候,要需要停止视频播放,视频数据使用硬件解码,OpenGL 渲染,在后台的时候,继续播放,可能会造成 App 崩溃。另外,涂鸦智能摄像机一般最多支持同时连接 5 路 P2P 通道(即支持 5 个手机同时连接),建议 App 在后台停留一段时间后,主动断开 P2P 连接,以释放资源。