Video Playback from Memory Card

Last Updated on : 2022-03-03 07:38:36download

Tuya smart camera support memory card recording. After the smart camera is inserted into the memory card, you can view the information and status of the memory card, and set the recording switch and mode. For details, please refer to Memory card management.

After the device saves the video recording in the memory card, it can play the video recording on the App side through the IPC SDK. Like the live video, it needs to connect to the p2p channel before starting playback. After the p2p channel is successfully connected, you can obtain the time information of the video clip recorded in the memory card on the device, and then play the video clip.

Video clip

The video clips saved in the memory card on the device can be as long as 10 minutes and as short as 10 seconds. The SDK supports viewing and playing video recordings on a day-by-day basis, and provides queries on which days are saved with video recordings in a month so that users can view them, and the query results are returned through the delegate method in TuyaSmartCameraDelegate.

Description

Query the days when video recordings are saved in a certain year and month.

- (void)queryRecordDaysWithYear:(NSUInteger)year month:(NSUInteger)month;

Parameters

Parameter Description
year Year, such as 2020
month Month, such as 2

Description

Query all video clips in a certain month and day.

- (void)queryRecordTimeSliceWithYear:(NSUInteger)year month:(NSUInteger)month day:(NSUInteger)day;

Parameters

Parameter Description
year Year, such as 2020
month Month, such as 2
day Day, such as 22

Delegate Description

Callback for querying the date of video recording.

- (void)camera:(id<TuyaSmartCameraType>)camera didReceiveRecordDayQueryData:(NSArray<NSNumber *> *)days;

Parameters

Parameter Description
camera Camera object
days An array of days with video recordings, such as @[@(1), @(2)] indicates the current month of the query, there are video recordings on the 1st,2nd

Delegate Description

Callback when querying all video clips in a day.

- (void)camera:(id<TuyaSmartCameraType>)camera didReceiveTimeSliceQueryData:(NSArray<NSDictionary *> *)timeSlices;

Parameters

Parameter Description
camera Camera object
timeSlices Array of time information of video clips for the day, failure returns empty array

Video clip time data

The element type in timeSlices is NSDictionary.

Field (Constant defined in SDK) Type Description
kTuyaSmartPlaybackPeriodStartDate NSDate Video clip start date
kTuyaSmartPlaybackPeriodStopDate NSDate Video clip end date
kTuyaSmartPlaybackPeriodStartTime NSNumber Unix timestamp of video clip start time
kTuyaSmartPlaybackPeriodStopTime NSNumber Unix timestamp of video clip end time

Video playback

After successfully obtaining the video clips of a certain day, you can start playing the video. It is worth noting that if you stop playing the video recording and then play live video, or the p2p connection is disconnected, reconnect to the p2p channel, and then play the video recording again, you need to re-acquire the video clip of the day, otherwise it may appear exception.

Description

To start playing a certain video recording, the range of playTime is:[startTime, stopTime).

- (void)startPlayback:(NSInteger)playTime startTime:(NSInteger)startTime stopTime:(NSInteger)stopTime;

Parameters

Parameter Description
playTime In this video, the time point to start playing, using Unix timestamp
startTime Start time of this video, using Unix timestamp
stopTime End time of this video, using Unix timestamp

Description

Pause playback.

- (void)pausePlayback;

Description

Resume playback.

- (void)resumePlayback;

Description

Stop play.

- (void)stopPlayback;

Description

Multiple speed playback

- (void)speedPlayWithPlayBackSpeed:(TuyaSmartCameraPlayBackSpeed)playBackSpeed;

Parameters

Parameter Description
playBackSpeed Playback speed, the specified playback peed needs device support

Delegate Description

Video playback started successfully.

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

Delegate Description

Video playback paused.

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

Delegate Description

Video playback resumed.

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

Delegate Description

Video has stopped playing.

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

Delegate Description

Video playback finished.

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

Flow chart

Video Playback from Memory Card

Example

ObjC

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

- (void)startPlayback {
	if (self.connected) {
		[self.camera queryRecordTimeSliceWithYear:2020 month:2 day:12];
		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) {
				// Failed to get configuration information
	}];
}

- (void)pausePlayback {
	[self.camera pausePlayback];
}

- (void)resumePlayback {
	[self.camera resumePlayback];
}

- (void)stopPlayback {
	[self.camera stopPlayback];
}

#pragma mark - TuyaSmartCameraDelegate

- (void)cameraDidConnected:(id<TuyaSmartCameraType>)camera {
	self.connected = YES;
		[camera queryRecordTimeSliceWithYear:2020 month:2 day:12];
}

- (void)cameraDisconnected:(id<TuyaSmartCameraType>)camera {
	self.connected = NO;
	self.playbacking = NO;
}

- (void)camera:(id<TuyaSmartCameraType>)camera didReceiveTimeSliceQueryData:(NSArray<NSDictionary *> *)timeSlices {
		if (timeSlices.count == 0) {
		return;
	}
	// start playback with first video clip
	self.timeSlicesInCurrentDay = [timeSlices copy];
	self.timeSlicesIndex = 0;
	NSDictionary *timeSlice = timeSlices.firstObject;
	NSInteger startTime = [timeSlice[kTuyaSmartTimeSliceStartTime] integerValue];
	NSInteger stopTime = [timeSlice[kTuyaSmartTimeSliceStopTime] integerValue];

	NSInteger playTime = startTime;
	[camera startPlayback:playTime startTime:startTime stopTime:stopTime];
}

- (void)camera:(id<TuyaSmartCameraType>)camera ty_didReceiveVideoFrame:(CMSampleBufferRef)sampleBuffer frameInfo:(TuyaSmartVideoFrameInfo)frameInfo {
	NSInteger index = self.timeSlicesIndex + 1;
	if (index >= self.timeSlicesInCurrentDay.count) {
		return;
	}
	NSDictionary *currentTimeSlice = [self.timeSlicesInCurrentDay objectAtIndex:self.timeSlicesIndex];
	NSInteger stopTime = [currentTimeSlice[kTuyaSmartTimeSliceStopTime] integerValue];
	// if timestamp of current frame is equal or greater than the end time of current video clip, play next video
	if (frameInfo.nTimeStamp >= stopTime) {
		NSDictionary *nextTimeSlice = [self.timeSlicesInCurrentDay objectAtIndex:index];
		NSInteger startTime = [nextTimeSlice[kTuyaSmartTimeSliceStartTime] integerValue];
			NSInteger stopTime = [nextTimeSlice[kTuyaSmartTimeSliceStopTime] integerValue];
			NSInteger playTime = startTime;
			[camera startPlayback:playTime startTime:startTime stopTime:stopTime];
	}
}

- (void)cameraDidBeginPlayback:(id<TuyaSmartCameraType>)camera {
	self.playbacking = YES;
	self.playbackPaused = NO;
		[self.view addSubview:camera.videoView];
}

- (void)cameraDidPausePlayback:(id<TuyaSmartCameraType>)camera {
	self.playbackPaused = YES;
}

- (void)cameraDidResumePlayback:(id<TuyaSmartCameraType>)camera {
	self.playbackPaused = NO;
}

- (void)cameraDidStopPlayback:(id<TuyaSmartCameraType>)camera {
	self.playbacking = NO;
	self.playbackPaused = NO;
}

- (void)cameraPlaybackDidFinished:(id<TuyaSmartCameraType>)camera {
	self.playbacking = NO;
	self.playbackPaused = NO;
}

- (void)camera:(id<TuyaSmartCameraType>)camera didOccurredErrorAtStep:(TYCameraErrorCode)errStepCode specificErrorCode:(NSInteger)errorCode {
		if (errStepCode == TY_ERROR_CONNECT_FAILED) {
		// p2p connect failed
		self.connected = NO;
	}
	else if (errStepCode == TY_ERROR_START_PLAYBACK_FAILED) {
		// start playback failed
		self.playbacking = NO;
			self.playbackPaused = NO;
	}
	else if (errStepCode == TY_ERROR_PAUSE_PLAYBACK_FAILED) {
				// pause playback failed
	}
	else if (errStepCode == TY_ERROR_RESUME_PLAYBACK_FAILED) {
				// resume playback failed
	}
}

Swift

func startPlayback() {
	if self.isConnected {
		self.camera.queryRecordTimeSlice(withYear: 2020, month: 2, day: 12)
		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
				// Failed to get configuration information
	}
}

func pausePlayback() {
	self.camera.pausePlayback()
}

func resumePlayback() {
	self.camera.resumePlayback()
}

func stopPlayback() {
	self.camera.stopPlayback()
}

func cameraDidConnected(_ camera: TuyaSmartCameraType!) {
	self.isConnected = true
	// start playback with first video clip
	camera.queryRecordTimeSlice(withYear: 2020, month: 2, day: 12)
}

func cameraDisconnected(_ camera: TuyaSmartCameraType!) {
	self.isConnected = false
	self.isPlaybacking = false
}

func camera(_ camera: TuyaSmartCameraType!, didReceiveTimeSliceQueryData timeSlices: [[AnyHashable : Any]]!) {
	guard timeSlices.count > 0 else {
		return;
	}
	// start playback with first video clip
	self.timeSlices = timeSlices
	self.timesliceIndex = 0
	let video = timeSlices.first!
	let startTime = video[kTuyaSmartTimeSliceStartTime] as! Int
	let stopTime = video[kTuyaSmartTimeSliceStopTime] as! Int

	let playTime = startTime
	camera.startPlayback(playTime, startTime: startTime, stopTime: stopTime)
}

func camera(_ camera: TuyaSmartCameraType!, ty_didReceiveVideoFrame sampleBuffer: CMSampleBuffer!, frameInfo: TuyaSmartVideoFrameInfo) {
	let index = self.timesliceIndex + 1
	guard index < self.timeSlices.count else {
		return
	}
	let currentTimeSlice = timeSlices[self.timesliceIndex]
	let endTime = currentTimeSlice[kTuyaSmartTimeSliceStopTime] as! Int
	guard frameInfo.nTimeStamp >= endTime else {
		return
	}
	// if timestamp of current frame is equal or greater than the end time of current video clip, play next video
	let nextTimeSlice = timeSlices.first!
	let startTime = nextTimeSlice[kTuyaSmartTimeSliceStartTime] as! Int
	let stopTime = nextTimeSlice[kTuyaSmartTimeSliceStopTime] as! Int
	let playTime = startTime
	camera.startPlayback(playTime, startTime: startTime, stopTime: stopTime)
}

func cameraDidBeginPlayback(_ camera: TuyaSmartCameraType!) {
	self.isPlaybacking = true
	self.isPlaybackPaused = false
	self.view.addSubview(camera.videoView())
}

func cameraDidPausePlayback(_ camera: TuyaSmartCameraType!) {
	self.isPlaybackPaused = true
}

func cameraDidResumePlayback(_ camera: TuyaSmartCameraType!) {
	self.isPlaybackPaused = false
}

func cameraDidStopPlayback(_ camera: TuyaSmartCameraType!) {
	self.isPlaybacking = false
	self.isPlaybackPaused = false
}

func cameraPlaybackDidFinished(_ camera: TuyaSmartCameraType!) {
	self.isPlaybacking = false
	self.isPlaybackPaused = false
}

func camera(_ camera: TuyaSmartCameraType!, didOccurredErrorAtStep errStepCode: TYCameraErrorCode, specificErrorCode errorCode: Int) {
	if errStepCode == TY_ERROR_CONNECT_FAILED  {
		// p2p connect failed
		self.isConnected = false
	}else if errStepCode == TY_ERROR_START_PLAYBACK_FAILED {
		// start playback failed
		self.isPlaybacking = false
		self.isPlaybackPaused = false
	}else if errStepCode == TY_ERROR_PAUSE_PLAYBACK_FAILED {
				// pause playback failed
	}else if errStepCode == TY_ERROR_RESUME_PLAYBACK_FAILED {
				// resume playback failed
	}
}

Note: During the live video, if you want to switch to video playback mode, you do not need to disconnect the p2p connection and then reconnect to the p2p channel, but you need to stop the live video playback before you get the video recording of the day to start playing.