#
# TI Voxel Viewer component.
#
# Copyright (c) 2015 Texas Instruments Inc.
#
from PySide import QtCore
import Voxel
import time
import threading
import os
# from PyVoxelViewer.common.Logger import Logger
[docs]class StreamSource(QtCore.QObject):
paused = QtCore.Signal()
resumed = QtCore.Signal()
stopped = QtCore.Signal()
beforestart = QtCore.Signal()
started = QtCore.Signal()
def __init__(self, name, parent = None):
super(StreamSource, self).__init__(parent)
self.callback = None
self.name = name
self.pos = 0
self.timestamp = 0
self.paus = False
self.frameStreamHandler = None
[docs] def isInitialized(self):
pass
[docs] def getName(self):
return self.name
[docs] def setCallback(self, callback):
self.callback = callback
[docs] def removeCallback(self):
self.callback = None
[docs] def start(self):
return False
[docs] def pause(self):
if self.isRunning():
self.paus = True
self.paused.emit()
return True
else:
return False
[docs] def resume(self):
if self.isRunning():
if self.isPaused():
self.paus = False
self.resumed.emit()
return True
else:
return False
else:
self.paus = False
return False
[docs] def stop(self):
return False
[docs] def isRunning(self):
return False
[docs] def isPaused(self):
return self.paus
[docs] def isSeekable(self):
return False
[docs] def isLiveStream(self):
return False
[docs] def length(self):
return 0
[docs] def currentPosition(self):
return self.pos
[docs] def currentTimestamp(self):
return self.timestamp
[docs] def seek(self, pos):
return False
[docs] def getROI(self):
return None
[docs] def getBinning(self):
return None
[docs] def getStreamParamf(self, name):
if self.frameStreamHandler is not None:
r, f = self.frameStreamHandler.getStreamParamf(name)
if r:
return f
else:
return 0
else:
return 0
[docs] def getDepthScalingFactor(self):
return self.getStreamParamf("depthScalingFactor")
[docs] def getAmplitudeScalingFactor(self):
return self.getStreamParamf("amplitudeScalingFactor")
[docs]class DepthCameraStreamSource(StreamSource):
def __init__(self, depthCamera):
super(DepthCameraStreamSource, self).__init__("Live Capture")
self.setDepthCamera(depthCamera)
[docs] def isInitialized(self):
return not (self.depthCamera is None)
[docs] def setDepthCamera(self, depthCamera):
self.depthCamera = depthCamera
self.frameStreamHandler = depthCamera
if self.depthCamera:
self.depthCamera.clearAllCallbacks()
self.depthCamera.registerCallback(Voxel.DepthCamera.FRAME_RAW_FRAME_UNPROCESSED, self.callbackInternal)
self.depthCamera.registerCallback(Voxel.DepthCamera.FRAME_RAW_FRAME_PROCESSED, self.callbackInternal)
self.depthCamera.registerCallback(Voxel.DepthCamera.FRAME_DEPTH_FRAME, self.callbackInternal)
self.depthCamera.registerCallback(Voxel.DepthCamera.FRAME_XYZI_POINT_CLOUD_FRAME, self.callbackInternal)
[docs] def start(self):
if self.isPaused():
return self.resume()
if self.depthCamera and not self.depthCamera.isRunning():
self.beforestart.emit()
if not self.depthCamera.start():
return False
self.started.emit()
return True
else:
return False
[docs] def isPaused(self):
if self.depthCamera:
return self.depthCamera.isPaused()
else:
return False
[docs] def pause(self):
if self.depthCamera:
if self.depthCamera.pause():
self.paused.emit()
return True
else:
return False
else:
return False
[docs] def resume(self):
if self.depthCamera:
if self.depthCamera.resume():
self.resumed.emit()
return True
else:
return False
else:
return False
[docs] def stop(self):
if self.isPaused():
self.resume()
if self.depthCamera:
if self.depthCamera.isRunning():
if not self.depthCamera.stop():
return False
self.stopped.emit()
return True
else:
self.stopped.emit()
return True
else:
return False
[docs] def isLiveStream(self):
return True
[docs] def isRunning(self):
if self.depthCamera:
return self.depthCamera.isRunning()
else:
return False
[docs] def callbackInternal(self, depthCamera, frame, type):
self.pos = frame.id
self.timestamp = frame.timestamp
if self.isPaused():
return
if self.callback:
self.callback(depthCamera, frame, type)
def __del__(self):
if self.isRunning():
self.stop()
del self.depthCamera
[docs]class FileStreamSource(StreamSource):
def __init__(self, filename, cameraSystem):
super(FileStreamSource, self).__init__(os.path.basename(filename))
self.filename = filename
self.runThread = None
self.running = False
self.cameraSystem = cameraSystem
self.frameStream = Voxel.FrameStreamReader(str(filename), cameraSystem)
self.frameStreamHandler = self.frameStream
[docs] def isInitialized(self):
return self.frameStream.isStreamGood()
[docs] def isLiveStream(self):
return False
[docs] def isRunning(self):
return self.running
[docs] def isSeekable(self):
return True
[docs] def currentPosition(self):
return self.frameStream.currentPosition()
[docs] def currentTimestamp(self):
if self.timestamp:
return self.timestamp
else:
return 0
[docs] def length(self):
return self.frameStream.size()
[docs] def seek(self, pos):
self.frameStream.seekTo(pos)
if not self.isRunning():
self.processNext()
[docs] def processNext(self):
if not self.frameStream.readNext():
return False
self.timestamp = self.frameStream.frames[Voxel.DepthCamera.FRAME_RAW_FRAME_UNPROCESSED].timestamp
self.frameID = self.frameStream.frames[Voxel.DepthCamera.FRAME_RAW_FRAME_UNPROCESSED].id
if self.callback:
self.callback(None, self.frameStream.frames[Voxel.DepthCamera.FRAME_RAW_FRAME_UNPROCESSED], Voxel.DepthCamera.FRAME_RAW_FRAME_UNPROCESSED)
self.callback(None, self.frameStream.frames[Voxel.DepthCamera.FRAME_RAW_FRAME_PROCESSED], Voxel.DepthCamera.FRAME_RAW_FRAME_PROCESSED)
self.callback(None, self.frameStream.frames[Voxel.DepthCamera.FRAME_DEPTH_FRAME], Voxel.DepthCamera.FRAME_DEPTH_FRAME)
self.callback(None, self.frameStream.frames[Voxel.DepthCamera.FRAME_XYZI_POINT_CLOUD_FRAME], Voxel.DepthCamera.FRAME_XYZI_POINT_CLOUD_FRAME)
if self.isPaused() or not self.isRunning():
self.frameStream.seekTo(self.frameStream.currentPosition() - 1)
return True
[docs] def runLoop(self):
lastTimeStamp = -1
lastFrameIndex = -1
while self.running:
t = time.time()
if not self.processNext():
self.running = False
self.stopped.emit()
t2 = (time.time() - t)*1E6
if lastTimeStamp > 0:
t = (self.timestamp - lastTimeStamp - t2)*1E-6
if lastFrameIndex > 0 and self.frameID > lastFrameIndex:
t /= (self.frameID - lastFrameIndex)
if t > 0:
time.sleep(t)
if not self.isPaused():
lastTimeStamp = self.timestamp
lastFrameIndex = self.frameID
[docs] def start(self):
if not self.frameStream.isStreamGood():
return False
if self.isPaused():
self.resume()
if self.currentPosition() >= self.length() - 1:
self.seek(0)
self.beforestart.emit()
self.running = True
self.runThread = threading.Thread(target = self.runLoop)
self.runThread.start()
self.started.emit()
return True
[docs] def pause(self):
if not super(FileStreamSource, self).pause():
return False
if self.isRunning() and self.runThread is not None and self.runThread.is_alive():
self.running = False
self.runThread.join()
self.running = False
self.runThread = None
return True
[docs] def stop(self):
if not self.isPaused():
if not self.pause():
return False
self.resume()
self.stopped.emit()
self.seek(0)
return True
def __del__(self):
self.stop()
[docs]class DepthCameraStreamController(QtCore.QObject):
started = QtCore.Signal()
beforestart = QtCore.Signal()
stopped = QtCore.Signal()
paused = QtCore.Signal()
resumed = QtCore.Signal()
sourceListChanged = QtCore.Signal()
sourceSelected = QtCore.Signal(int)
onDepthCameraSet = QtCore.Signal()
def __init__(self, cameraSystem, depthCamera = None):
super(DepthCameraStreamController, self).__init__()
self.depthCamera = depthCamera
self.cameraSystem = cameraSystem
self.depthCameraSourceIndex = -1
self.callbacks = []
self.sources = []
for i in range(0, Voxel.DepthCamera.FRAME_TYPE_COUNT):
self.callbacks.append([])
if self.depthCamera is not None:
self.addDepthCameraSource()
[docs] def addDepthCameraSource(self):
self.sources.append(DepthCameraStreamSource(self.depthCamera))
self.depthCameraSourceIndex = len(self.sources) - 1
self.sourceListChanged.emit()
self.setCurrentSource(self.depthCameraSourceIndex)
[docs] def getCameraSystem(self):
return self.cameraSystem
[docs] def disconnectDepthCamera(self, onlyFromUI = False):
if not self.depthCamera:
return
self.stop()
# if not onlyFromUI:
# if not self.cameraSystem.disconnect(self.depthCamera):
# Logger.writeLog(Voxel.LOG_ERROR, 'Failed to disconnect depth camera')
#
del self.depthCamera
self.depthCamera = None
if self.currentSource == self.sources[self.depthCameraSourceIndex]:
self.currentSource = None
del self.sources[self.depthCameraSourceIndex]
self.depthCameraSourceIndex = -1
self.sourceListChanged.emit()
[docs] def setDepthCamera(self, depthCamera):
self.depthCamera = depthCamera
self.onDepthCameraSet.emit()
if self.depthCameraSourceIndex >= 0:
r = self.currentSource.isRunning()
if self.currentSource == self.sources[self.depthCameraSourceIndex] and r:
self.currentSource.stop()
self.sources[self.depthCameraSourceIndex].setDepthCamera(depthCamera)
if self.currentSource == self.sources[self.depthCameraSourceIndex] and r:
self.currentSource.start()
else:
self.addDepthCameraSource()
self.sources[self.depthCameraSourceIndex].setDepthCamera(depthCamera)
self.sourceSelected.emit(self.currentSourceIndex)
[docs] def getDepthCamera(self):
return self.depthCamera
[docs] def getCurrentSource(self):
if hasattr(self, 'currentSource'):
return self.currentSource
else:
return None
[docs] def setCurrentSource(self, pos):
if pos >= len(self.sources):
print "DepthCameraStreamController: Invalid source ID = ", pos, ", Valid = [0, ", (len(self.sources) - 1)
return False
if hasattr(self, 'currentSource') and self.currentSource is not None:
self.currentSource.stop()
self.currentSource.removeCallback()
self.currentSource.started.disconnect(self.started)
self.currentSource.beforestart.disconnect(self.beforestart)
self.currentSource.stopped.disconnect(self.stopped)
self.currentSource.paused.disconnect(self.paused)
self.currentSource.resumed.disconnect(self.resumed)
self.currentSource = self.sources[pos]
self.currentSourceIndex = pos
self.currentSource.setCallback(self.callbackInternal)
self.currentSource.started.connect(self.started)
self.currentSource.beforestart.connect(self.beforestart)
self.currentSource.stopped.connect(self.stopped)
self.currentSource.paused.connect(self.paused)
self.currentSource.resumed.connect(self.resumed)
self.sourceSelected.emit(pos)
return True
[docs] def registerCallback(self, type, callback):
self.callbacks[type].append(callback)
return True
[docs] def clearCallback(self, type, callback):
for i in self.callbacks[type]:
if i == callback:
self.callbacks[type].remove(i)
return True
return False
[docs] def getSources(self):
return self.sources
[docs] def addFileStreamSource(self, filename):
i = 0
for s in self.sources:
if isinstance(s, FileStreamSource):
if s.filename == filename:
return i
i = i + 1
self.sources.append(FileStreamSource(filename, self.cameraSystem))
self.sourceListChanged.emit()
return i
[docs] def removeStreamSource(self, index):
if index < 0 or index >= len(self.sources):
return False
if isinstance(self.sources[index], DepthCameraStreamSource):
self.disconnectDepthCamera(onlyFromUI = True)
del self.sources[index]
self.sourceListChanged.emit()
return True
[docs] def isRunning(self):
if hasattr(self, 'currentSource') and self.currentSource is not None:
return self.currentSource.isRunning()
else:
return False
[docs] def isPaused(self):
if hasattr(self, 'currentSource') and self.currentSource is not None:
return self.currentSource.isPaused()
else:
return False
[docs] def callbackInternal(self, depthCamera, frame, type):
for f in self.callbacks[type]:
f(depthCamera, frame, type)
[docs] def start(self):
if hasattr(self, 'currentSource') and self.currentSource is not None:
return self.currentSource.start()
else:
return False
[docs] def pause(self):
if hasattr(self, 'currentSource') and self.currentSource is not None:
return self.currentSource.pause()
else:
return False
[docs] def stop(self):
if hasattr(self, 'currentSource') and self.currentSource is not None:
return self.currentSource.stop()
else:
return False