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;}"
            )
        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 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
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)
  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])
예제 #6
0
    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
예제 #7
0
    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