"""
:filename: SamplePlugin.py
:author: roar@tordivel.no
:requirements: Scorpion 10.1.1.569 or higher
VideoRecorder - Scorpion plugin for creating video from Scorpion GUI
::
1.0.0.15, 11nov2015, RL: modified for autodoc
1.0.0.14, 25jan2014, roar@tordivel.no
format combobox accepts any text (FOURCC)
1.0.0.13, 24jan2014, roar@tordivel.no
added video format
1.0.0.12, 17jan2014, RL:
added hints and adjusted control position in config dialog
1.0.0.11, 16jan2014, RL:
added start recording on start option
1.0.0.10, 18apr2013, RL:
new filename <prefix>_<YYYYMMDD>_<nnnnnn>.avi
1.0.0.9, 10oct2012, RL:
using icon stripes
added allowOnlineRecording
1.0.0.8, 08oct2012, TV:
new metro icons
1.0.0.7, 06sep2012, RL:
fixed video source mapping when creating video
fixed button hints
new icons
1.0.0.6, 04sep2012, RL:
uses <Storage>\Video folder
added filename prefix
changed button order/captions/hint
1.0.0.5, 30aug2012, RL:
added simulation button
1.0.0.4, 30aug2012, RL:
using SpeedButtons with graphis
added configuration dialog
1.0.0.3, 21aug2012, RL:
layout improvements
1.0.0.2, 10aug2012, RL:
resizes controls
added autoStart flag
added start/stopRecording methods
added shortcut
added configure method
1.0.0.1, 02jul2012, RL:
created
"""
__version__ = '1.0.0.15'
import os
import datetime
from Scorpion import RegisterCallback,UnregisterCallback,GetCameraImages,FindFiles,CreateVideoWriter,PluginChanged
from Scorpion import GetStringValue,GetBoolValue,GetControlByHandle,CreateControlVideoWriter,ExecuteCmd,CreateOKCancelDialog
VIDEOSOURCES = ['Image pane','Left pane','Right pane','Application'] #GUI names
INTERNALSOURCES = ['ImageView' ,'LeftPane' ,'RightPane' ,''] #Scorpion internal names
VIDEOFORMATS = ['DIB','CVID','MSVC','IYUV'] #known available formats
#-----------------------------------------------------------------------------
# VideoRecorderPlugin configuration dilaog
#-----------------------------------------------------------------------------
[docs]class VideoRecorderPlugin(object):
def __init__(self,cntr,name):
def addbttn(caption,hint,filename,onClick):
bttn=self.cntr.addControl('SpeedButton',10,6)
bttn.caption=caption
bttn.font.size=self.cntr.font.size
bttn.layout=2
bttn.height=self.bttnsize
bttn.width=self.bttnsize
bttn.flat=True
bttn.glyphName=os.path.join(os.path.split(__file__)[0],filename)
bttn.numGlyphs=4
bttn.hint=hint
bttn.showHint=True
bttn.onClick=onClick
self.bttns.append(bttn)
return bttn
cntr.deleteControls() #delete previous added controls if any
src=list(GetCameraImages().names)+VIDEOSOURCES #get available sources
self.iname=cntr.iname #full path name of control
self.name=name #this plugins name
self.cntr=cntr #keep reference to container
self.cntr.onResize=self.cntrResize #hook up on size events
self.bttnsize=60 #default button size
self.source=src[0] #defult source
self.fps=1 #default framerate
self.format=VIDEOFORMATS[0] #default video format
self.autostart=True #flag to start/stop on record bttn
self.autorecord=False #flag to start/stop record on start/stop
self.shortcut='' #may contain F1..F12
self.prefix='Video' #filename prefix
self.filename='' #current filename
self.frameCount=0 #current frames
self.allowOnlineRecording=True #enables/disables recording due to
self.writer=None #the videowriter object
self.bttns=[] #list of all buttons
self.folder=os.path.join(GetStringValue('System.Storage'),'Video')
if not os.path.exists(self.folder):os.makedirs(self.folder)
self.bRecord = addbttn('Record', 'start/stop recording', 'RecordImageStrip.bmp', self.bRecordClick)
self.bPlay = addbttn('Play Video', 'play last recorded video', 'PlayImageStrip.bmp', self.bPlayClick)
self.bExplore = addbttn('Video Folder', 'open video folder', 'FolderImageStrip.bmp', self.bExploreClick)
self.bSequence = addbttn('Buffer', 'select file buffer', 'SelectImageStrip.bmp', self.bSequenceClick)
self.bReset = addbttn('Reset', 'reset file buffer', 'SkipBackwardImageStrip.bmp', self.bResetClick)
self.bSimulation = addbttn('Offline', 'toggle online/offline ', 'SnapshotImageStrip.bmp', self.bSimulationClick)
self.bRecord.groupIndex=1 #to enable up/down
self.bRecord.allowAllUp=True #to enable toggling of single button
self.bSimulation.groupIndex=2 #to enable up/down
self.bSimulation.allowAllUp=True #to enable toggling of single button
self.miConfig=self.cntr.addMenuItem('Configure') #add configuration popup menu
self.miConfig.onClick=self.miConfigClick
self.lblState=self.cntr.addControl('Label',0,self.bRecord.bottom+6)
self.lblState.caption=''
self.lblState.autosize=False
self.lblState.alignment=2
RegisterCallback('Actions.BeforeStart',self.actionsBeforeStart)
RegisterCallback('Actions.AfterStop',self.actionsAfterStop)
RegisterCallback('Actions.AfterInspect',self.actionsAfterInspect)
RegisterCallback('System.SimulationChanged',self.systemSimulationChanged)
RegisterCallback('System.AccessControlChanged',self.systemAccessControlChanged)
self.registerShortcut()
self.cntrResize(None,None)
self.enableControls()
[docs] def getConfig(self):
'''
returns plugin configuration as string
'''
from SPB import CreateSpb
spb=CreateSpb()
#create a spb instance, populate with the plugin configuration
#and return the xml string
spb.setText('type',self.__class__.__name__) #configuration type
spb.setInt('version',6) #current config version
spb.setText('source',self.source)
spb.setText('prefix',self.prefix)
spb.setFloat('fps',self.fps)
spb.setText('format',self.format)
spb.setBool('autostart',self.autostart)
spb.setBool('autorecord',self.autorecord)
spb.setText('shortcut',self.shortcut)
spb.setBool('allowOnlineRec',self.allowOnlineRecording)
return spb.xml
[docs] def setConfig(self,value):
'''
set plugin configuration from the string 'value'
'''
from SPB import CreateSpb
spb=CreateSpb(value)
#extract plugin configuration from the spb object
if spb.getText('type')==self.__class__.__name__:
if spb.getInt('version')>0:
self.source=spb.getText('source')
self.fps=spb.getFloat('fps')
if spb.getInt('version')>1:
self.autostart=spb.getBool('autostart')
self.shortcut=spb.getText('shortcut')
if spb.getInt('version')>2:
self.format=spb.getText('format')
if self.format=='RAW':self.format='DIB' #for compatibilty
if spb.getInt('version')>3:
self.prefix=spb.getText('prefix')
if spb.getInt('version')>4:
self.allowOnlineRecording=spb.getBool('allowOnlineRec')
if spb.getInt('version')>5:
self.autorecord=spb.getBool('autorecord')
self.registerShortcut()
self.enableControls()
[docs] def enableControls(self):
'''
enable controls due to operation state
'''
running=GetBoolValue('System.Running')
service=GetBoolValue('System.Service') or GetBoolValue('System.Settings')
simulation=GetBoolValue('System.CameraSimulation')
self.bRecord.enabled=self.allowOnlineRecording or simulation
self.bRecord.down=self.writer<>None
self.bPlay.enabled=not running and os.path.exists(self.filename)
self.bReset.enabled=simulation
self.bSequence.enabled=not running
self.bSimulation.enabled=not running
self.bSimulation.down=simulation
self.bExplore.enabled=not running and os.path.exists(self.folder)
self.miConfig.enabled=service
self.miConfig.visible=service
[docs] def registerShortcut(self):
'''
register for shortcut events
'''
for i in range(1,13):
UnregisterCallback('Actions.F%i'%i,self.actionsFn)
if self.shortcut=='F%i'%i:
RegisterCallback('Actions.F%i'%i,self.actionsFn)
[docs] def getNextFileno(self,path,prefix,cnt):
'''
return unique filename by adding trailing integer
'''
lst=FindFiles(os.path.join(path,'%s%s.avi'%(prefix,'?'*cnt)))
if len(lst):
s=os.path.splitext(lst[-1])[0] #get filename without ext
return int(s[len(prefix):len(s)])+1 #remove prefix and return trailing no+1
return 1
[docs] def getNextFilename(self):
'''
return next unique filename
'''
path=os.path.join(GetStringValue('System.Storage'),'Video')
prefix='%s_%s_'%(self.prefix,datetime.date.today().strftime('%Y%m%d'))
return os.path.join(path,'%s%06i.avi'%(prefix,self.getNextFileno(path,prefix,6)))
[docs] def startRecording(self):
'''
start recording if not recording
'''
if self.writer==None:
if self.source==VIDEOSOURCES[0]: src=INTERNALSOURCES[0]
elif self.source==VIDEOSOURCES[1]: src=INTERNALSOURCES[1]
elif self.source==VIDEOSOURCES[2]: src=INTERNALSOURCES[2]
elif self.source==VIDEOSOURCES[3]: src=INTERNALSOURCES[3]
else: src=self.source
self.writer=CreateControlVideoWriter(src)
self.filename=self.getNextFilename()
print 'filename',self.filename,self.format
period=int(round(1000/self.fps))
if os.path.exists(self.filename):os.remove(self.filename)
if self.writer.open(self.filename,period,self.format):
self.lblState.caption='%s - %i'%(os.path.relpath(self.filename,self.folder),self.writer.frameCount)
self.bRecord.down=True
else:
self.stopRecording()
self.lblState.caption='Error opening %s'%(os.path.relpath(self.filename,self.folder))
self.enableControls()
return self.writer<>None
[docs] def stopRecording(self):
'''
stop recording if active
'''
if self.writer:
self.bRecord.down=False
self.lblState.caption='%s - %i frames recorded'%(os.path.relpath(self.filename,self.folder),self.writer.frameCount)
self.writer.close()
self.writer=None
self.enableControls()
return self.writer==None
[docs] def playVideo(self,filename):
'''
play video
'''
os.startfile(filename,'open')
[docs] def playLastVideo(self):
'''
play last video
'''
self.playVideo(self.filename)
[docs] def selectSequence(self):
'''
select sequence
'''
GetCameraImages().configure(2)
self.enableControls()
[docs] def reset(self):
'''
reset sequence
'''
GetCameraImages().resetFilenames()
[docs] def explore(self):
'''
launch explorer in video folder
'''
os.startfile(self.folder,'open')
[docs] def cntrResize(self,sender,args):
'''
center buttons in panel
'''
l=int(self.cntr.clientWidth/2-((len(self.bttns)*(self.bttns[0].width)+(len(self.bttns)-1)*4))/2)
for b in self.bttns:
b.left=l
l=b.right+4
self.lblState.width=self.cntr.clientWidth
[docs] def bSequenceClick(self,sender,args):
'''
select guard tagname
'''
self.selectSequence()
[docs] def bResetClick(self,sender,args):
'''
reset sequence
'''
self.reset()
[docs] def bRecordClick(self,sender,args):
'''
start/stop recording
'''
if self.writer==None:
if self.startRecording() and self.autostart:
ExecuteCmd('start','')
elif self.writer:
if self.stopRecording() and self.autostart:
ExecuteCmd('stop','')
[docs] def bPlayClick(self,sender,args):
'''
view last video
'''
self.playLastVideo()
[docs] def bSimulationClick(self,sender,args):
'''
toggle simulation
'''
GetCameraImages().simulation=not GetCameraImages().simulation
self.enableControls()
[docs] def bExploreClick(self,sender,args):
'''
launch explorer in video folder
'''
self.explore()
[docs] def miConfigClick(self,sender,args):
'''
launch configuration dialog
'''
if GetBoolValue('System.Service') or GetBoolValue('System.Settings'):
self.configure()
[docs] def systemAccessControlChanged(self,settings,service):
'''
update rights
'''
self.enableControls()
[docs] def actionsBeforeStart(self):
'''
start
'''
if self.autorecord: self.startRecording()
self.enableControls()
[docs] def actionsAfterStop(self):
'''
end of video if recording
'''
self.stopRecording()
[docs] def actionsAfterInspect(self):
'''
add image to video
'''
if GetBoolValue('System.Running') and self.writer:
if self.writer.addFrame():
self.lblState.caption='%s - %d'%(os.path.relpath(self.filename,self.folder),self.writer.frameCount)
else:
self.lblState.caption='addFrame failed'
[docs] def systemSimulationChanged(self,simulation,folder):
'''
'''
self.enableControls()
[docs] def actionsFn(self):
'''
start/stop on shortcut
'''
if self.writer==None:
self.startRecording()
else:
self.stopRecording()
[docs]def CreatePlugin(hWnd, name=''):
'''
Scorpion Plugin Stub - Required
'''
cntr=GetControlByHandle(hWnd)
return VideoRecorderPlugin(cntr,name)