class MyGui(QtWidgets.QMainWindow): debug=False # debug=True def __init__(self,pardic,parent=None): super(MyGui, self).__init__() self.pardic=pardic self.initVars() self.setupUi() if (self.debug): return self.openValkka() self.start_streams() def initVars(self): pass def setupUi(self): self.setGeometry(QtCore.QRect(100,100,800,800)) self.w=QtWidgets.QWidget(self) self.setCentralWidget(self.w) self.lay=QtWidgets.QGridLayout(self.w) self.videoframes =[] self.addresses=self.pardic["cams"] def openValkka(self): self.livethread=LiveThread( # starts live stream services (using live555) name ="live_thread", # verbose=True, verbose=False, affinity=self.pardic["live affinity"] ) # create widgets before starting OpenGLThread and reserving frames cw=0 # widget / window index self.win_ids=[] for address in self.addresses: for cc in range(0,self.pardic["replicate"]): fr =TestWidget0(self.w) win_id =int(fr.winId()) nrow=self.pardic["videos per row"] print(pre,"setupUi: layout index, address : ",cw//nrow,cw%nrow,address) self.lay.addWidget(fr,cw//nrow,cw%nrow) self.videoframes.append(fr) self.win_ids.append(win_id) cw+=1 win_iter =iter(self.win_ids) self.openglthread=OpenGLThread( # starts frame presenting services name ="mythread", n_720p =self.pardic["n_720p"], # reserve stacks of YUV video frames for various resolutions n_1080p =self.pardic["n_1080p"], n_1440p =self.pardic["n_1440p"], n_4K =self.pardic["n_4K"], # naudio =self.pardic["naudio"], # obsolete # verbose =True, verbose =False, msbuftime=self.pardic["msbuftime"], affinity=self.pardic["gl affinity"] ) if (self.openglthread.hadVsync()): w=QtWidgets.QMessageBox.warning(self,"VBLANK WARNING","Syncing to vertical refresh enabled\n THIS WILL DESTROY YOUR FRAMERATE\n Disable it with 'export vblank_mode=0' for nvidia proprietary drivers, use 'export __GL_SYNC_TO_VBLANK=0'") tokens =[] self.chains=[] a =self.pardic["dec affinity start"] cw=0 # widget / window index cs=1 # slot / stream count for address in self.addresses: # now livethread and openglthread are running if (a>self.pardic["dec affinity stop"]): a=self.pardic["dec affinity start"] print(pre,"openValkka: setting decoder thread on processor",a) chain=BasicFilterchain( # decoding and branching the stream happens here livethread =self.livethread, openglthread=self.openglthread, address =address, slot =cs, affinity =a, # verbose =True verbose =False, msreconnect =10000, # flush_when_full =True flush_when_full =False, # time_correction =TimeCorrectionType_dummy, # Timestamp correction type: TimeCorrectionType_none, TimeCorrectionType_dummy, or TimeCorrectionType_smart (default) # time_correction =TimeCorrectionType_smart, # # by default, no need to specify recv_buffer_size =0, # Operating system socket ringbuffer size in bytes # 0 means default # recv_buffer_size =1024*800, # 800 KB reordering_mstime =0 # Reordering buffer time for Live555 packets in MILLIseconds # 0 means default # reordering_mstime =300 ) self.chains.append(chain) # important .. otherwise chain will go out of context and get garbage collected .. for cc in range(0,self.pardic["replicate"]): token =self.openglthread.connect(slot=cs,window_id=next(win_iter)) # present frames with slot number cs at window win_id tokens.append(token) cw+=1 cs+=1 chain.decodingOn() # tell the decoding thread to start its job a+=1 def closeValkka(self): self.livethread.close() for chain in self.chains: chain.close() self.chains =[] self.widget_pairs =[] self.videoframes =[] self.openglthread.close() def start_streams(self): pass def stop_streams(self): pass def closeEvent(self,e): print(pre,"closeEvent!") self.stop_streams() self.closeValkka() e.accept()
class MyGui(QtWidgets.QMainWindow): debug = False # debug=True def __init__(self, pardic, parent=None): super(MyGui, self).__init__() self.pardic = pardic self.initVars() self.setupUi() if (self.debug): return self.openValkka() self.start_streams() def initVars(self): pass def setupUi(self): self.setGeometry(QtCore.QRect(100, 100, 800, 800)) self.w = QtWidgets.QWidget(self) self.setCentralWidget(self.w) self.lay = QtWidgets.QGridLayout(self.w) self.videoframes = [] self.widget_pairs = [] self.addresses = self.pardic["cams"] def openValkka(self): # setValkkaLogLevel(loglevel_debug) core.setLiveOutPacketBuffermaxSize(95000) # whoa # check this out: # http://lists.live555.com/pipermail/live-devel/2013-April/016803.html self.livethread = LiveThread( # starts live stream services (using live555) name="live_thread", # verbose=True, verbose=False, affinity=self.pardic["live affinity"]) self.livethread2 = LiveThread( # second live thread for sending multicast streams name="live_thread2", # verbose=True, verbose=False, affinity=self.pardic["live2 affinity"]) self.openglthread = OpenGLThread( # starts frame presenting services name="mythread", n_720p=self.pardic[ "n_720p"], # reserve stacks of YUV video frames for various resolutions n_1080p=self.pardic["n_1080p"], n_1440p=self.pardic["n_1440p"], n_4K=self.pardic["n_4K"], # naudio =self.pardic["naudio"], # obsolete # verbose =True, verbose=False, msbuftime=self.pardic["msbuftime"], affinity=self.pardic["gl affinity"]) if (self.openglthread.hadVsync()): w = QtWidgets.QMessageBox.warning( self, "VBLANK WARNING", "Syncing to vertical refresh enabled\n THIS WILL DESTROY YOUR FRAMERATE\n Disable it with 'export vblank_mode=0' for nvidia proprietary drivers, use 'export __GL_SYNC_TO_VBLANK=0'" ) tokens = [] self.chains = [] a = self.pardic["dec affinity start"] mport = self.pardic["mcast_start_port"] cw = 0 # widget / window index cs = 1 # slot / stream count for address in self.addresses: # now livethread and openglthread are running if (a > self.pardic["dec affinity stop"]): a = self.pardic["dec affinity start"] print(pre, "openValkka: setting decoder thread on processor", a) chain = MulticastFilterchain( # decoding and branching the stream happens here incoming_livethread=self.livethread, outgoing_livethread=self.livethread2, openglthread=self.openglthread, address=address, multicast_address=mcast_address, multicast_port=mport, slot=cs, affinity=a, # verbose =True verbose=False, msreconnect=10000) self.chains.append( chain ) # important .. otherwise chain will go out of context and get garbage collected .. # replicate=self.pardic["replicate"] replicate = 1 for cc in range(0, replicate): if ("no_qt" in self.pardic): # create our own x-windowses win_id = self.openglthread.createWindow(show=True) else: # *** Choose one of the following sections *** # (1) Let Valkka create the windows/widget # use this: we get a window with correct parametrization # win_id =self.openglthread.createWindow(show=False) # fr =getForeignWidget(self.w, win_id) if (valkka_xwin == False): # (2) Let Qt create the widget fr = TestWidget0(self.w) win_id = int(fr.winId()) else: # """ # (3) Again, let Valkka create the window, but put on top a translucent widget (that catches mouse gestures) win_id = self.openglthread.createWindow(show=False) widget_pair = WidgetPair(self.w, win_id, TestWidget0) fr = widget_pair.getWidget() self.widget_pairs.append(widget_pair) # """ nrow = self.pardic["videos per row"] print(pre, "setupUi: layout index, address : ", cw // nrow, cw % nrow, address) self.lay.addWidget(fr, cw // nrow, cw % nrow) # print(pre,"setupUi: layout index, address : ",cw//4,cw%4,address) # self.lay.addWidget(fr,cw//4,cw%4) self.videoframes.append(fr) token = self.openglthread.connect( slot=cs, window_id=win_id ) # present frames with slot number cs at window win_id tokens.append(token) cw += 1 cs += 1 # TODO: crash when repeating the same slot number ..? chain.decodingOn() # tell the decoding thread to start its job a += 1 mport += 4 def closeValkka(self): self.livethread.close() for chain in self.chains: chain.close() self.widget_pairs = [] self.videoframes = [] self.openglthread.close() self.livethread2.close() def start_streams(self): pass def stop_streams(self): pass def closeEvent(self, e): print(pre, "closeEvent!") self.stop_streams() self.closeValkka() e.accept()
class MyGui(QtWidgets.QMainWindow): debug=False # debug=True def __init__(self): super(MyGui, self).__init__() # self.pardic=pardic self.initVars() self.setupUi() if (self.debug): return self.openValkka() self.startProcesses() def initVars(self): self.messages=[] self.mode="file" self.slot_reserved=False def setupUi(self): self.setGeometry(QtCore.QRect(100,100,800,800)) self.w=QtWidgets.QWidget(self) self.setCentralWidget(self.w) self.lay=QtWidgets.QVBoxLayout(self.w) # divide window into three parts self.upper =QtWidgets.QWidget(self.w) self.lower =QtWidgets.QWidget(self.w) self.lowest =QtWidgets.QWidget(self.w) self.lay.addWidget(self.upper) self.lay.addWidget(self.lower) self.lay.addWidget(self.lowest) # upper part: license plate list and the video self.upperlay =QtWidgets.QHBoxLayout(self.upper) self.msg_list =QtWidgets.QTextEdit(self.upper) self.video_area =QtWidgets.QWidget(self.upper) self.video_lay =QtWidgets.QGridLayout(self.video_area) self.upperlay.addWidget(self.msg_list) self.upperlay.addWidget(self.video_area) self.msg_list.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self.video_area.setSizePolicy(QtWidgets.QSizePolicy.Expanding,QtWidgets.QSizePolicy.Expanding) # lower part: [Open File] [Close Live] [Play] [Stop] [Rewind] self.lowerlay =QtWidgets.QHBoxLayout(self.lower) self.open_file_button =QtWidgets.QPushButton("Open File", self.lower) self.close_file_button=QtWidgets.QPushButton("Close File",self.lower) self.play_button =QtWidgets.QPushButton("Play",self.lower) self.stop_button =QtWidgets.QPushButton("Stop",self.lower) self.rewind_button =QtWidgets.QPushButton("<<", self.lower) self.lowerlay.addWidget(self.open_file_button) self.lowerlay.addWidget(self.close_file_button) self.lowerlay.addWidget(self.play_button) self.lowerlay.addWidget(self.stop_button) self.lowerlay.addWidget(self.rewind_button) self.open_file_button.clicked. connect(self.open_file_button_slot) self.close_file_button.clicked.connect(self.close_file_button_slot) self.play_button.clicked. connect(self.play_button_slot) self.stop_button.clicked. connect(self.stop_button_slot) self.rewind_button.clicked. connect(self.rewind_button_slot) # lowest part: some text self.lowestlay=QtWidgets.QVBoxLayout(self.lowest) self.infotext =QtWidgets.QLabel("info text",self.lowest) self.lowestlay.addWidget(self.infotext) def openValkka(self): self.livethread=LiveThread( # starts live stream services (using live555) name ="live_thread", verbose=False ) self.filethread=FileThread( name ="file_thread", verbose=False ) self.openglthread=OpenGLThread( # starts frame presenting services name ="mythread", n_720p =10, n_1080p =10, n_1440p =10, n_4K =10, verbose =False, msbuftime=100, affinity=-1 ) if (self.openglthread.hadVsync()): w=QtWidgets.QMessageBox.warning(self,"VBLANK WARNING","Syncing to vertical refresh enabled\n THIS WILL DESTROY YOUR FRAMERATE\n Disable it with 'export vblank_mode=0' for nvidia proprietary drivers, use 'export __GL_SYNC_TO_VBLANK=0'") cc=1 self.chain=ShmemFilterchain1( # decoding and branching the stream happens here openglthread=self.openglthread, slot =cc, # this filterchain creates a shared memory server shmem_name ="test_studio_file_"+str(cc), shmem_image_dimensions =(1920//4,1080//4), # Images passed over shmem are quarter of the full-hd reso shmem_image_interval =1000, # YUV => RGB interpolation to the small size is done each 1000 milliseconds and passed on to the shmem ringbuffer shmem_ringbuffer_size =10 # Size of the shmem ringbuffer ) shmem_name, n_buffer, shmem_image_dimensions =self.chain.getShmemPars() # print(pre,"shmem_name, n_buffer, n_bytes",shmem_name,n_buffer,n_bytes) self.process=QValkkaMovementDetectorProcess("process_"+str(cc),shmem_name=shmem_name, n_buffer=n_buffer, image_dimensions=shmem_image_dimensions) self.process.signals.start_move.connect(self.set_moving_slot) self.process.signals.stop_move. connect(self.set_still_slot) if (valkka_xwin): # (1) Let OpenGLThread create the window self.win_id =self.openglthread.createWindow(show=False) self.widget_pair =WidgetPair(self.video_area,self.win_id,TestWidget0) self.video =self.widget_pair.getWidget() else: # (2) Let Qt create the window self.video =QtWidgets.QWidget(self.video_area) self.win_id =int(self.video.winId()) self.video_lay.addWidget(self.video,0,0) self.token =self.openglthread.connect(slot=cc,window_id=self.win_id) self.chain.decodingOn() # tell the decoding thread to start its job # finally, give the multiprocesses to a qthread that's reading their message pipe self.thread =QValkkaThread(processes=[self.process]) def startProcesses(self): self.process.start() self.thread.start() def stopProcesses(self): print(pre,"stopProcesses :",self.process) self.process.stop() self.thread.stop() print(pre,"QThread stopped") def closeValkka(self): self.livethread.close() self.chain.close() self.chain =None self.openglthread.close() def closeEvent(self,e): print(pre,"closeEvent!") self.stopProcesses() self.closeValkka() super().closeEvent(e) # *** slot **** def open_file_button_slot(self): if (self.slot_reserved): self.infotext.setText("Close the current file first") return fname=QtWidgets.QFileDialog.getOpenFileName(filter="*.mkv")[0] if (len(fname)>0): print(pre,"open_file_button_slot: got filename",fname) self.chain.setFileContext(fname) self.filethread.openStream(self.chain.file_ctx) self.slot_reserved=True if (self.chain.fileStatusOk()): self.infotext.setText("Opened file "+fname) else: self.infotext.setText("Can't play file "+fname) else: self.infotext.setText("No file opened") def close_file_button_slot(self): if (not self.slot_reserved): self.infotext.setText("Open a file first") return self.filethread.closeStream(self.chain.file_ctx) self.slot_reserved=False self.infotext.setText("Closed file") def open_live_button_slot(self): pass def play_button_slot(self): if (self.mode=="file"): if (not self.slot_reserved): self.infotext.setText("Open a file first") return self.filethread.playStream(self.chain.file_ctx) else: pass def rewind_button_slot(self): if (self.mode=="file"): if (not self.slot_reserved): self.infotext.setText("Open a file first") return self.chain.file_ctx.seektime_=0; self.filethread.seekStream(self.chain.file_ctx) else: pass def stop_button_slot(self): if (self.mode=="file"): if (not self.slot_reserved): self.infotext.setText("Open a file first") return self.filethread.stopStream(self.chain.file_ctx) else: pass def set_still_slot(self): self.infotext.setText("still") self.messages.append("Movement stopped at ") if (len(self.messages)>10): self.messages.pop(0) st="" for message in self.messages: st+=message+"\n" self.msg_list.setText(st) def set_moving_slot(self): self.infotext.setText("MOVING") self.messages.append("Movement started at ") if (len(self.messages)>10): self.messages.pop(0) st="" for message in self.messages: st+=message+"\n" self.msg_list.setText(st)
class MyGui(QtWidgets.QMainWindow): class Frame: """Create a frame with text (indicating movement) and a video frame. The video frame is created from a "foreign" window (created by Valkka) """ def __init__(self, parent, win_id): self.widget = QtWidgets.QWidget(parent) self.lay = QtWidgets.QVBoxLayout(self.widget) self.text = QtWidgets.QLabel("", self.widget) self.text_stylesheet = self.text.styleSheet() # create the foreign widget / normal widget pair # normal widget of class TestWidget0 self.widget_pair = WidgetPair(self.widget, win_id, TestWidget0) self.video = self.widget_pair.getWidget() self.lay.addWidget(self.text) self.lay.addWidget(self.video) self.text.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self.video.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.set_still() def setText(self, txt): self.text.setText(txt) def set_still(self): self.setText("still") self.widget.setStyleSheet(self.text_stylesheet) def set_moving(self): self.setText("MOVING") self.widget.setStyleSheet( "QLabel {border: 2px; border-style:solid; border-color: red; margin:0 px; padding:0 px; border-radius:8px;}" ) class NativeFrame: """Create a frame with text (indicating movement) and a video frame. The video frame is created by Qt. """ def __init__(self, parent): self.widget = QtWidgets.QWidget(parent) self.lay = QtWidgets.QVBoxLayout(self.widget) self.text = QtWidgets.QLabel("", self.widget) self.text_stylesheet = self.text.styleSheet() self.video = QtWidgets.QWidget(self.widget) self.lay.addWidget(self.text) self.lay.addWidget(self.video) self.text.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self.video.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.set_still() def getWindowId(self): return int(self.video.winId()) def setText(self, txt): self.text.setText(txt) def set_still(self): self.setText("still") self.widget.setStyleSheet(self.text_stylesheet) def set_moving(self): self.setText("MOVING") self.widget.setStyleSheet( "QLabel {border: 2px; border-style:solid; border-color: red; margin:0 px; padding:0 px; border-radius:8px;}" ) debug = False # debug=True def __init__(self, pardic, parent=None): super(MyGui, self).__init__() self.pardic = pardic self.initVars() self.setupUi() if (self.debug): return self.openValkka() def initVars(self): pass def setupUi(self): self.setGeometry(QtCore.QRect(100, 100, 800, 800)) self.w = QtWidgets.QWidget(self) self.setCentralWidget(self.w) self.lay = QtWidgets.QGridLayout(self.w) self.frames = [] # frames with movement detector alert and video self.addresses = self.pardic["cams"] def openValkka(self): # some constant values # Images passed over shmem are quarter of the full-hd reso shmem_image_dimensions = (1920 // 4, 1080 // 4) # YUV => RGB interpolation to the small size is done each 1000 # milliseconds and passed on to the shmem ringbuffer shmem_image_interval = 1000 shmem_ringbuffer_size = 10 # the very first thing: create & start multiprocesses cs = 1 self.processes = [] for address in self.addresses: shmem_name = "test_studio_" + str(cs) process = QValkkaMovementDetectorProcess( "process_" + str(cs), shmem_name=shmem_name, n_buffer=shmem_ringbuffer_size, image_dimensions=shmem_image_dimensions) self.processes.append(process) print(self.processes) # Give the multiprocesses to a qthread that's reading their message # pipe self.thread = QValkkaThread(processes=self.processes) # starts the multiprocesses self.startProcesses() # ..so, forks have been done. Now we can spawn threads self.livethread = LiveThread( # starts live stream services (using live555) name="live_thread", verbose=False, affinity=self.pardic["live affinity"]) self.openglthread = OpenGLThread( # starts frame presenting services name="mythread", # reserve stacks of YUV video frames for various resolutions n_720p=self.pardic["n_720p"], n_1080p=self.pardic["n_1080p"], n_1440p=self.pardic["n_1440p"], n_4K=self.pardic["n_4K"], # naudio =self.pardic["naudio"], # obsolete verbose=False, msbuftime=self.pardic["msbuftime"], affinity=self.pardic["gl affinity"]) if (self.openglthread.hadVsync()): w = QtWidgets.QMessageBox.warning( self, "VBLANK WARNING", "Syncing to vertical refresh enabled\n THIS WILL DESTROY YOUR FRAMERATE\n Disable it with 'export vblank_mode=0' for nvidia proprietary drivers, use 'export __GL_SYNC_TO_VBLANK=0'" ) tokens = [] self.chains = [] self.frames = [] cs = 1 cc = 0 a = self.pardic["dec affinity start"] for address in self.addresses: # now livethread and openglthread are running if (a > self.pardic["dec affinity stop"]): a = self.pardic["dec affinity start"] print(pre, "openValkka: setting decoder thread on processor", a) # this filterchain creates a shared memory server # identifies shared memory buffer must be same as in the # multiprocess chain = ShmemFilterchain( # decoding and branching the stream happens here livethread=self.livethread, openglthread=self.openglthread, address=address, slot=cs, affinity=a, shmem_name="test_studio_" + str(cs), shmem_image_dimensions=shmem_image_dimensions, shmem_image_interval=shmem_image_interval, shmem_ringbuffer_size=shmem_ringbuffer_size, msreconnect=10000 # time_correction =TimeCorrectionType_smart # this is the default, no need to specify ) self.chains.append(chain) if (valkka_xwin): win_id = self.openglthread.createWindow(show=False) frame = self.Frame(self.w, win_id) else: frame = self.NativeFrame(self.w) win_id = frame.getWindowId() # print(pre,"setupUi: layout index, address : ",cc//4,cc%4,address) # self.lay.addWidget(frame.widget,cc//4,cc%4) nrow = self.pardic["videos per row"] print(pre, "setupUi: layout index, address : ", cc // nrow, cc % nrow, address) self.lay.addWidget(frame.widget, cc // nrow, cc % nrow) self.frames.append(frame) token = self.openglthread.connect(slot=cs, window_id=win_id) tokens.append(token) # take corresponding analyzer multiprocess process = self.processes[cc] process.createClient( ) # creates the shared memory client at the multiprocess # connect signals to the nested widget process.signals.start_move.connect(frame.set_moving) process.signals.stop_move.connect(frame.set_still) chain.decodingOn() # tell the decoding thread to start its job cs += 1 # TODO: crash when repeating the same slot number ..? a += 1 cc += 1 def startProcesses(self): self.thread.start() for p in self.processes: p.start() def stopProcesses(self): for p in self.processes: p.stop() print(pre, "stopping QThread") self.thread.stop() print(pre, "QThread stopped") def closeValkka(self): self.livethread.close() for chain in self.chains: chain.close() self.chains = [] self.widget_pairs = [] self.videoframes = [] self.openglthread.close() def closeEvent(self, e): print(pre, "closeEvent!") self.stopProcesses() self.closeValkka() super().closeEvent(e)
class MyGui(QtWidgets.QMainWindow): debug = False # debug=True def __init__(self, pardic, valkkafs, parent=None): super(MyGui, self).__init__() self.pardic = pardic self.valkkafs = valkkafs self.initVars() self.setupUi() if (self.debug): return self.openValkka() self.start_streams() def initVars(self): pass def setupUi(self): self.setGeometry(QtCore.QRect(100, 100, 800, 800)) self.w = QtWidgets.QWidget(self) self.setCentralWidget(self.w) self.lay = QtWidgets.QGridLayout(self.w) self.videoframes = [] self.widget_pairs = [] self.addresses = self.pardic["cams"] # self.rec_window = QtWidgets.QMainWindow(self) # self.rec_window = QtWidgets.QTabWidget(None) self.rec_window = MyTabWidget(None) self.rec_window.setGeometry(QtCore.QRect(50, 50, 800, 800)) self.rec_window.show() self.rec_video_tab = QtWidgets.QWidget(None) self.rec_video_lay = QtWidgets.QVBoxLayout(self.rec_video_tab) self.rec_calendar_tab = QtWidgets.QWidget(None) self.rec_calendar_lay = QtWidgets.QVBoxLayout(self.rec_calendar_tab) self.rec_window.addTab(self.rec_video_tab, "Video") self.rec_window.addTab(self.rec_calendar_tab, "Calendar") self.rec_video_area = QtWidgets.QWidget(self.rec_video_tab) self.rec_video_area.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.rec_video_area_lay = QtWidgets.QGridLayout(self.rec_video_area) self.rec_video_lay.addWidget(self.rec_video_area) # timeline self.timelinewidget = TimeLineWidget(datetime.date.today(), parent=self.rec_video_area) # self.timelinewidget.setLogLevel(logging.DEBUG) self.rec_video_lay.addWidget(self.timelinewidget) # buttons self.buttons = QtWidgets.QWidget(self.rec_video_area) self.buttons_lay = QtWidgets.QHBoxLayout(self.buttons) self.play_button = QtWidgets.QPushButton("play", self.buttons) self.stop_button = QtWidgets.QPushButton("stop", self.buttons) self.zoom_to_fs_button = QtWidgets.QPushButton("limits", self.buttons) self.buttons_lay.addWidget(self.play_button) self.buttons_lay.addWidget(self.stop_button) self.buttons_lay.addWidget(self.zoom_to_fs_button) self.rec_video_lay.addWidget(self.buttons) # calendar self.calendarwidget = CalendarWidget(datetime.date.today(), parent=self.rec_calendar_tab) self.rec_calendar_lay.addWidget(self.calendarwidget) def openValkka(self): self.valkkafsmanager = ValkkaFSManager( self.valkkafs, # read = False, # debugging # cache = False, # debugging # write = False # debugging ) self.playback_controller = PlaybackController( calendar_widget=self.calendarwidget, timeline_widget=self.timelinewidget, valkkafs_manager=self.valkkafsmanager, play_button=self.play_button, stop_button=self.stop_button, zoom_to_fs_button=self.zoom_to_fs_button) self.livethread = LiveThread( # starts live stream services (using live555) name="live_thread", # verbose=True, verbose=False, affinity=self.pardic["live affinity"]) self.openglthread = OpenGLThread( # starts frame presenting services name="mythread", # reserve stacks of YUV video frames for various resolutions n_720p=self.pardic["n_720p"], n_1080p=self.pardic["n_1080p"], n_1440p=self.pardic["n_1440p"], n_4K=self.pardic["n_4K"], # naudio =self.pardic["naudio"], # obsolete verbose=True, # verbose=False, msbuftime=self.pardic["msbuftime"], affinity=self.pardic["gl affinity"]) if (self.openglthread.hadVsync()): w = QtWidgets.QMessageBox.warning( self, "VBLANK WARNING", "Syncing to vertical refresh enabled\n THIS WILL DESTROY YOUR FRAMERATE\n Disable it with 'export vblank_mode=0' for nvidia proprietary drivers, use 'export __GL_SYNC_TO_VBLANK=0'" ) tokens = [] self.chains = [] a = self.pardic["dec affinity start"] cw = 0 # widget / window index cs = 1 # slot / stream count for address in self.addresses: # now livethread and openglthread are running if (a > self.pardic["dec affinity stop"]): a = self.pardic["dec affinity start"] print(pre, "openValkka: setting decoder thread on processor", a) if use_live: chain_live = ValkkaFSLiveFilterchain( # decoding and branching the stream happens here valkkafsmanager=self.valkkafsmanager, id_rec=cs, # identifies the stream in ValkkaFS livethread=self.livethread, address=address, slot=cs, affinity=a, # verbose =True verbose=False, msreconnect=10000, # Reordering buffer time for Live555 packets in MILLIseconds # 0 means default reordering_mstime=0 # reordering_mstime =300 ) rec_slot = cs + 100 # live and rec slot numbers must be kept separated .. chain_rec = ValkkaFSFileFilterchain( # decoding and branching the stream happens here valkkafsmanager=self.valkkafsmanager, id_rec=cs, # identifies the stream in ValkkaFS slot=rec_slot, affinity=a, # verbose =True verbose=False) # send yuv to OpenGLThread if use_live: chain_live.connect_to_yuv("yuv_to_opengl_" + str(cs), self.openglthread.getInput()) chain_rec.connect_to_yuv("yuv_to_opengl_" + str(cs), self.openglthread.getInput()) # important .. otherwise chain will go out of context and get # garbage collected .. if use_live: self.chains.append(chain_live) self.chains.append(chain_rec) if ("no_qt" in self.pardic): # create our own x-windowses win_id = self.openglthread.createWindow(show=True) win_id_rec = self.openglthread.createWindow(show=True) else: # *** Choose one of the following sections *** # (1) Let Valkka create the windows/widget # use this: we get a window with correct parametrization # win_id =self.openglthread.createWindow(show=False) # fr =getForeignWidget(self.w, win_id) if (valkka_xwin == False): # (2) Let Qt create the widget fr = TestWidget0(self.w) win_id = int(fr.winId()) fr_rec = TestWidget0(self.rec_video_area) win_id_rec = int(fr_rec.winId()) else: # """ # (3) Again, let Valkka create the window, but put on top a translucent widget (that catches mouse gestures) win_id = self.openglthread.createWindow(show=False) widget_pair = WidgetPair(self.w, win_id, TestWidget0) fr = widget_pair.getWidget() self.widget_pairs.append(widget_pair) win_id_rec = self.openglthread.createWindow(show=False) widget_pair = WidgetPair(self.rec_video_area, win_id_rec, TestWidget0) fr_rec = widget_pair.getWidget() self.widget_pairs.append(widget_pair) # """ nrow = self.pardic["videos per row"] print(pre, "setupUi: layout index, address : ", cw // nrow, cw % nrow, address) self.lay.addWidget(fr, cw // nrow, cw % nrow) self.rec_video_area_lay.addWidget(fr_rec, cw // nrow, cw % nrow) self.videoframes.append(fr) self.videoframes.append(fr_rec) # present frames with slot number cs at window win_id # rec_slot = cs # debug print(pre, "setupUi: live:", cs, win_id) print(pre, "setupUi: rec :", rec_slot, win_id_rec) token = self.openglthread.connect(slot=cs, window_id=win_id) tokens.append(token) token = self.openglthread.connect(slot=rec_slot, window_id=win_id_rec) tokens.append(token) cw += 1 cs += 1 if use_live: chain_live.decodingOn( ) # tell the decoding thread to start its job chain_rec.decodingOn() a += 1 def closeValkka(self): self.livethread.close() self.valkkafsmanager.close() for chain in self.chains: chain.close() self.chains = [] self.widget_pairs = [] self.videoframes = [] self.openglthread.close() # time.sleep(5) def start_streams(self): pass def stop_streams(self): pass def closeEvent(self, e): print("\n", pre, "closeEvent!\n") self.stop_streams() self.closeValkka() self.rec_window.forceClose() # self.rec_window.close() e.accept()
class MyGui(QtWidgets.QMainWindow): debug = False # debug=True def __init__(self, pardic, parent=None): super(MyGui, self).__init__() # print(pre,"Qapp=",QtCore.QCoreApplication.instance()) self.pardic = pardic self.initVars() self.setupUi() if (self.debug): return self.openValkka() self.start_streams() def initVars(self): pass def setupUi(self): self.desktop_handler = DesktopHandler() print(self.desktop_handler) self.setGeometry(QtCore.QRect(100, 100, 800, 800)) self.w = QtWidgets.QWidget(self) self.setCentralWidget(self.w) self.lay = QtWidgets.QGridLayout(self.w) self.videoframes = [] self.widget_pairs = [] self.addresses = self.pardic["cams"] def openValkka(self): self.livethread = LiveThread( # starts live stream services (using live555) name="live_thread", # verbose=True, verbose=False, affinity=self.pardic["live affinity"]) self.openglthread = OpenGLThread( # starts frame presenting services name="mythread", n_720p=self.pardic[ "n_720p"], # reserve stacks of YUV video frames for various resolutions n_1080p=self.pardic["n_1080p"], n_1440p=self.pardic["n_1440p"], n_4K=self.pardic["n_4K"], # naudio =self.pardic["naudio"], # obsolete # verbose =True, verbose=False, msbuftime=self.pardic["msbuftime"], affinity=self.pardic["gl affinity"], x_connection=":0.0" # x_connection =":0.1" # works .. video appears on the other xscreen ) """ # this results in a segfault print("> starting second OpenGLThread") # testing: start another OpenGLThread self.openglthread2=OpenGLThread( # starts frame presenting services name ="mythread2", n_720p =self.pardic["n_720p"], # reserve stacks of YUV video frames for various resolutions n_1080p =self.pardic["n_1080p"], n_1440p =self.pardic["n_1440p"], n_4K =self.pardic["n_4K"], # naudio =self.pardic["naudio"], # obsolete # verbose =True, verbose =False, msbuftime=self.pardic["msbuftime"], affinity=self.pardic["gl affinity"], x_connection =":0.1" # works .. video appears on the other xscreen ) print("> second OpenGLThread started") """ if (self.openglthread.hadVsync()): w = QtWidgets.QMessageBox.warning( self, "VBLANK WARNING", "Syncing to vertical refresh enabled\n THIS WILL DESTROY YOUR FRAMERATE\n Disable it with 'export vblank_mode=0' for nvidia proprietary drivers, use 'export __GL_SYNC_TO_VBLANK=0'" ) tokens = [] self.chains = [] a = self.pardic["dec affinity start"] cw = 0 # widget / window index cs = 1 # slot / stream count ntotal = len(self.addresses) * self.pardic["replicate"] nrow = self.pardic["videos per row"] ncol = max((ntotal // self.pardic["videos per row"]) + 1, 2) for address in self.addresses: # now livethread and openglthread are running if (a > self.pardic["dec affinity stop"]): a = self.pardic["dec affinity start"] print(pre, "openValkka: setting decoder thread on processor", a) chain = BasicFilterchain( # decoding and branching the stream happens here livethread=self.livethread, openglthread=self.openglthread, address=address, slot=cs, affinity=a, # verbose =True verbose=False, msreconnect=10000, # flush_when_full =True flush_when_full=False, # time_correction =TimeCorrectionType_dummy, # Timestamp correction type: TimeCorrectionType_none, TimeCorrectionType_dummy, or TimeCorrectionType_smart (default) time_correction=TimeCorrectionType_smart, recv_buffer_size= 0, # Operating system socket ringbuffer size in bytes # 0 means default # recv_buffer_size =1024*800, # 800 KB reordering_mstime= 0 # Reordering buffer time for Live555 packets in MILLIseconds # 0 means default # reordering_mstime =300 ) self.chains.append( chain ) # important .. otherwise chain will go out of context and get garbage collected .. for cc in range(0, self.pardic["replicate"]): if ("no_qt" in self.pardic): # create our own x-windowses win_id = self.openglthread.createWindow(show=True) else: # *** Choose one of the following sections *** # (1) Let Valkka create the windows/widget # use this: we get a window with correct parametrization # win_id =self.openglthread.createWindow(show=False) # fr =getForeignWidget(self.w, win_id) if (valkka_xwin == False): # (2) Let Qt create the widget fr = TestWidget0(None) win_id = int(fr.winId()) else: # """ # (3) Again, let Valkka create the window, but put on top a translucent widget (that catches mouse gestures) win_id = self.openglthread.createWindow(show=False) widget_pair = WidgetPair(None, win_id, TestWidget0) fr = widget_pair.getWidget() self.widget_pairs.append(widget_pair) # """ print(pre, "setupUi: layout index, address : ", cw // nrow, cw % nrow, address) # self.lay.addWidget(fr,cw//nrow,cw%nrow) # floating windows instead container = VideoContainer(None, fr, n=0) container.getWidget().setGeometry( self.desktop_handler.getGeometry( nrow, ncol, cw % nrow, cw // nrow)) container.getWidget().show() self.videoframes.append(container) token = self.openglthread.connect( slot=cs, window_id=win_id ) # present frames with slot number cs at window win_id tokens.append(token) cw += 1 cs += 1 # TODO: crash when repeating the same slot number ..? chain.decodingOn() # tell the decoding thread to start its job a += 1 def closeValkka(self): self.livethread.close() for chain in self.chains: chain.close() self.chains = [] self.widget_pairs = [] self.videoframes = [] self.openglthread.close() def start_streams(self): pass def stop_streams(self): pass def closeEvent(self, e): print(pre, "closeEvent!") self.stop_streams() self.closeValkka() e.accept()