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):
    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):
    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)
Beispiel #4
0
    print("mstime callback", mstime)

# create OpenGLThread (for drawing video) and AVThread (for decoding)
glthread = OpenGLThread(name="gl_thread")
ctx = core.FrameFifoContext()
avthread = core.AVThread(
    "avthread",
    glthread.getInput(),
    ctx)
av_in_filter = avthread.getFrameFilter()

avthread.startCall()
avthread.decodingOnCall()

# create an X-window
window_id = glthread.createWindow()

# map frames with slot 1 to that window
glthread.newRenderGroup(window_id)
context_id = glthread.newRenderContext(1, window_id, 0)

valkkafs = ValkkaFS.loadFromDirectory(dirname="/home/sampsa/tmp/testvalkkafs")
# manager = ValkkaFSManager(valkkafs, cb)
manager = ValkkaFSManager(valkkafs)

# manager.timeCallback__(1547796192621)
# paska

a = valkkafs.getBlockTable()
# print(a[:,0:10])
i=0
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()
Beispiel #6
0
class MyGui(QtWidgets.QMainWindow):
    class QtFrame:
        def __init__(self, parent, win_id):
            self.widget = QtWidgets.QWidget(parent)
            self.lay = QtWidgets.QVBoxLayout(self.widget)

            self.widget_pair = WidgetPair(self.widget, win_id, TestWidget0)
            self.video = self.widget_pair.getWidget()
            self.lay.addWidget(self.video)

        def getWindowId(self):
            return int(self.widget.winId())

    debug = False

    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.setWindowTitle('Vision alarm system')
        self.resize(1200, 800)

        self.menuBar().addMenu('Add Camera')
        self.menuBar().addMenu('Remove camera')

        self.main = QtWidgets.QWidget(self)
        self.setCentralWidget(self.main)
        self.w = QtWidgets.QWidget(self)
        # self.setCentralWidget(self.w)

        self.mainlay = QtWidgets.QVBoxLayout(self.main)
        self.mainlay.setSpacing(0)
        self.mainlay.setContentsMargins(0, 0, 0, 0)

        self.wlay = QtWidgets.QGridLayout(self.w)
        self.alert = QtWidgets.QTextEdit()

        self.mainlay.addWidget(self.w, 75)
        self.mainlay.addWidget(self.alert, 25)

        self.frames = []  # i currently don't know what it is used for
        self.addresses = self.pardic["cams"]
        print(self.addresses)

    def openValkka(self):

        # RGB Shared memory
        shmem_image_dimensions = (1920 // 4, 1080 // 4)
        shmem_image_interval = 1000
        shmem_rignbuffer_size = 10

        # Frag MP4 Shared memory
        shmem_buffers = 10
        shmem_name = "FragMP4Shmem"
        cellsize = 1024 * 1024 * 3
        timeout = 1000

        cs = 1
        cc = 1
        self.processes = []
        for address in self.addresses:
            shmem_name = "camera" + str(cs)
            # print("shmem name is {} for process number {} ".format(shmem_name, cc))
            process = QValkkaFireDetectorProcess(
                "process" + str(cs),
                shmem_name=shmem_name,
                n_buffer=shmem_rignbuffer_size,
                image_dimensions=shmem_image_dimensions)
            self.processes.append(process)
            cs += 1
        print(self.processes)

        # Give the multiprocesses to a gthread that's reading their message / thread will be listening to the processes !?

        self.thread = QValkkaThread(processes=self.processes)

        # start the multiprocesses
        self.startProcesses()

        # Now that we successfully forked our multiprocesses lets spawn threads

        self.livethread = LiveThread(name="live",
                                     verbose=False,
                                     affinity=self.pardic["live_affinity"])
        self.openglthread = OpenGLThread(
            name="mythread",
            # reserve stacks of YUV video frames for various resolutions
            n_720p=50,
            n_1080p=50,
            n_1440p=50,
            n_4K=50,
            verbose=False,
            msbuftime=100,
            affinity=-1)
        # if (self.openglthread.hadVsync()):
        #     q = QtWidgets.QMessageBox.warning(self,
        #                                       "VBLANK WARNING",
        #                                       "Syncing to vertical refresh enabled \n THIS WILL DESTROY YOUR FRAMERATE\n disable it using 'export vblank_mode=0'")

        tokens = []
        self.chains = []
        self.frames = []

        cs = 1
        cc = 0

        x = 0
        y = 0
        cam_count = 0
        a = self.pardic["dec affinity start"]
        for address in self.addresses:

            # Livethread/openglthread are running
            print('address :', address)
            if (a > self.pardic["dec affinity stop"]):
                a = self.pardic["dec affinity start"]

            chain = VisionAlarmFilterChain(
                # decoding and branching happens here
                livethread=self.livethread,
                openglthread=self.openglthread,
                address=address,
                slot=cs,
                affinity=a,
                shmem_name="camera" + str(cs),
                shmem_image_dimensions=shmem_image_dimensions,
                shmem_image_interval=shmem_image_interval,
                shmem_ringbuffer_size=shmem_rignbuffer_size,
                msreconnect=1000,
                frag_shmem_buffers=shmem_buffers,
                frag_shmem_name=shmem_name,
                frag_shmem_cellsize=cellsize,
                frag_shmem_timeout=timeout,
            )
            self.chains.append(chain)

            win_id = self.openglthread.createWindow(show=False)
            frame = self.QtFrame(self.w, win_id)

            # print('setting up layout')
            if y > 1:
                x = 1
                y = 0
            self.wlay.addWidget(frame.widget, x, y)
            y += 1
            token = self.openglthread.connect(slot=cs, window_id=win_id)
            tokens.append(token)

            # take corresponding multiprocess
            process = self.processes[cc]
            process.createClient(
            )  # creates the shared memory client at the multiprocess
            # connect signals to the nested widget

            process.signals.Fire_detected.connect(self.addAlert)

            chain.decodingOn()  # start the decoding thread
            cs += 1
            a += 1
            cc += 1
            # FragMP4 shmem client
            client = FragMP4ShmemClient(name=shmem_name,
                                        n_ringbuffer=shmem_buffers,
                                        n_size=cellsize,
                                        mstimeout=timeout,
                                        verbose=False)

    def startProcesses(self):
        self.thread.start()
        for p in self.processes:
            p.start()

    def stopProcesses(self):
        for p in self.processes:
            p.stop()
        print("stopping QThread")
        self.thread.stop()
        print("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("closeEvent!")
        self.stopProcesses()
        self.closeValkka()
        super().closeEvent()

    # Slot
    def addAlert(self):
        print('inside addAlert ')
        self.alert.append('Fire Detected on camera number 1')
        pass
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()
Beispiel #8
0
chain = BasicFilterchain(  # decoding and branching the stream happens here
    livethread=livethread,
    openglthread=openglthread,
    address="rtsp://*****:*****@192.168.1.41",
    slot=1,
    affinity=-1,
    verbose=False,
    msreconnect=10000  # if no frames in ten seconds, try to reconnect
)
"""<rtf>
BasicFilterchain takes as an argument the LiveThread and OpenGLThread instances.  It creates the relevant connections between the threads.

Next, create an x-window, map stream to the screen, and start decoding:
<rtf>"""
# create a window
win_id = openglthread.createWindow()

# create a stream-to-window mapping
token = openglthread.connect(
    slot=1,
    window_id=win_id)  # present frames with slot number 1 at window win_id

# start decoding
chain.decodingOn()
# stream for 20 secs
time.sleep(20)
"""<rtf>
Close threads in beginning-to-end order
<rtf>"""
livethread.close()
chain.close()