def receiver(self):
        """
		Connect to the RTSP server and receive the selected video (see :attr:`video`).
		"""
        VTLOG.info("Starting GStreamer receiver...")
        self.pipeline = parse_launch(
            'rtspsrc name=source ! tee name=t ! queue ! ' + self.depay +
            self.__add + ' ! filesink name=sink1 t. ! queue \
				! decodebin ! videorate skip-to-first=True ! video/x-raw-yuv,framerate=' +
            self.conf['framerate'] + '/1 ! filesink name=sink2')
        source = self.pipeline.get_by_name('source')
        sink1 = self.pipeline.get_by_name('sink1')
        sink2 = self.pipeline.get_by_name('sink2')
        source.props.location = self.url
        source.props.protocols = self.conf['protocols']
        location = self.conf['tempdir'] + self.conf['num'] + '.' + self.conf[
            'codec']
        self.files['received'].append(location)
        sink1.props.location = location
        location = self.conf['tempdir'] + self.conf['num'] + '.yuv'
        self.files['received'].append(location)
        sink2.props.location = location
        pad = sink2.get_pad("sink")
        pad.connect("notify::caps", self.__notifyCaps)
        self.__play()
        VTLOG.info("GStreamer receiver stopped")
    def __play(self):
        """
		Attach event handler, set state to *playing* and run the loop (see :attr:`loop`).
		"""
        self.pipeline.get_bus().add_watch(self.__events)
        self.pipeline.set_state(STATE_PLAYING)
        self.loop = MainLoop()
        self.loop.run()
        VTLOG.debug("GStreamer: Loop stopped")
 def __ping(self):
     """
     Ping to server (4 echoes).
     """
     from scapy.all import IP, ICMP, send
     from time import sleep
     sleep(0.5)
     VTLOG.info("Pinging...")
     for i in range(0, 4):
         send(IP(dst=self.conf['ip'])/ICMP(seq=i), verbose=False)
         sleep(0.5)
 def __saveMeasures(self, measures):
     """
     Save measures to disc (with standard module :mod:`pickle`).
     
     :param list measures: List of measures.
     """
     VTLOG.info("Saving measures...")
     from pickle import dump
     for measure in measures:
         f = open(self.conf['tempdir'] + self.conf['num'] + '_' + measure['name'] + '.pkl', "wb")
         dump(measure, f)
         f.close()
Beispiel #5
0
 def run(self, q):
     """
     Start packet sniffing and save the capture.
     
     :param Queue q: Queue to communicate with the main thread.
     """
     VTLOG.info("Starting sniffer...")
     expr = 'host ' + self.conf['ip']
     cap = self.sniff(iface=self.conf['iface'], filter=expr)
     location = self.conf['tempdir'] + self.conf['num'] + '.cap'
     wrpcap(location, cap)
     q.put(location)
     VTLOG.info("Sniffer stopped")
 def run(self):
     """
     Run registered measures. For each measure in :attr:`measures`, this method calls :meth:`Measure.calculate`.
     
     :returns: The list of measures.
     :rtype: list
     """
     measures = []
     for measure in self.measures:
         VTLOG.info("- Measuring: " + measure.data['name'])
         try:
             measures.append(measure.calculate())
         except Exception, e:
             VTLOG.error(e)
Beispiel #7
0
 def getBSm(self, measures):
     """
     Get bit-stream measures.
     
     :param measures: Selected bit-stream measures.
     :type measures: string or list
     
     :returns: Calculated bit-stream measures.
     :rtype: list
     """
     VTLOG.info("----------getBSm-----------")
     measures = BSmeter(measures, self.codecdata).run()
     VTLOG.info("---------------------------")
     return measures
Beispiel #8
0
 def getQoSm(self, measures):
     """
     Get QoS measures.
     
     :param measures: Selected QoS measures.
     :type measures: string or list
     
     :returns: Calculated QoS measures.
     :rtype: list
     """
     VTLOG.info("----------getQoSm----------")
     measures = QoSmeter(measures, self.packetdata).run()
     VTLOG.info("---------------------------")
     return measures
 def onCloseWindow(self, event):
     """
     Show a dialog to verify exit.
     """
     # dialog to verify exit (including menuExit)
     dlg = wx.MessageDialog(self, "Do you want to exit?", "Exit", wx.YES_NO | wx.ICON_QUESTION)
     result = dlg.ShowModal()
     dlg.Destroy()
     if result == wx.ID_YES:
         try:
             self.pipeline.set_state(STATE_NULL)
         except:
             pass
         VTLOG.removeHandler(self.hdlr)
         self.Destroy() # frame
Beispiel #10
0
 def __init__(self, selected, data):
     """
     **On init:** Register selected bit-stream measures.
     
     :param selected: Selected bit-stream measures.
     :type selected: string or list
     :param tuple data: Collected bit-stream parameters.
     """
     Meter.__init__(self)
     VTLOG.info("Starting BSmeter...")
     if 'streameye' in selected:
         self.measures.append(StreamEye(data))
     if 'refstreameye' in selected:
         self.measures.append(RefStreamEye(data))
     if 'gop' in selected:
         self.measures.append(GOP(data))
     if 'iflr' in selected:
         self.measures.append(IFrameLossRate(data))
 def __loadData(self, videodata, size, codec):
     """
     Load raw video data and coded video data.
     
     :param videodata: (see :attr:`VideoTester.gstreamer.RTSPclient.files`)
     
     :returns: Coded video data object (see :class:`VideoTester.video.YUVvideo`) and raw video data object (see :class:`VideoTester.video.CodedVideo`).
     :rtype: tuple
     """
     VTLOG.info("Loading videos...")
     from VideoTester.video import YUVvideo, CodedVideo
     codecdata = {}
     rawdata = {}
     for x in videodata.keys():
         if x != 'original':
             codecdata[x] = CodedVideo(videodata[x][0], codec)
         rawdata[x] = YUVvideo(videodata[x][1], size)
         VTLOG.info("+++")
     return codecdata, rawdata
Beispiel #12
0
 def extract(p):
     """
     Extract information from a UDP packet.
     
     :param Packet p: UDP packet.
     """
     ptype = ord(str(p[UDP].payload)[1]) & 0x7F  #Delete RTP marker
     p[UDP].decode_payload_as(RTP)
     if ptype == self.ptype:
         #Avoid duplicates while running on loopback interface
         if p[RTP].sequence not in self.sequences:
             self.lengths.append(p.len)
             self.times.append(p.time)
             self.sequences.append(p[RTP].sequence + self.__add)
             self.timestamps.append(p[RTP].timestamp)
             VTLOG.debug("UDP/RTP packet found. Sequence: " +
                         str(p[RTP].sequence))
             if p[RTP].sequence == 65535:
                 self.__add += 65536
 def __init__(self, file, gui=False):
     """
     **On init:** Some initialization code.
     
     :param file: Path to a configuration file (string) or parsed configuration file (dictionary).
     :type file: string or dictionary
     :param boolean gui: True if :class:`Client` is called from GUI. False otherwise.
     
     :raises: Bad configuration file or path.
     
     .. warning::
         If ``gui == True``, `file` MUST be a dictionary. Otherwise, `file` MUST be a string.
     """
     VT.__init__(self)
     from os.path import exists
     from VideoTester.config import TEMP, makeDir
     if gui:
         self.conf = file
     else:
         try:
             #: Dictionary of configuration options.
             self.conf = dict(self.parseConf(file, "client"))
         except:
             VTLOG.error("Bad configuration file or path")
             exit()
     #: Path to the selected video.
     self.video = '/'.join([self.path, dict(self.videos)[self.conf['video']]])
     self.conf['tempdir'] = TEMP + self.conf['video'] + '_' + self.conf['codec'] + '_' + self.conf['bitrate'] + '_' + self.conf['framerate'] + '_' + self.conf['protocols'] + '/'
     makeDir(self.conf['tempdir'])
     i , j = 0, True
     while j and i < 100:
         if i < 10:
             num = '0' + str(i)
         else:
             num = str(i)
         i = i + 1
         j = exists(self.conf['tempdir'] + num + '.yuv')
     if j:
         VTLOG.error("The TEMP directory is full")
         exit()
     #: Numerical prefix for temporary files.
     self.conf['num'] = num
Beispiel #14
0
 def __init__(self, selected, data):
     """
     **On init:** Register selected video quality measures.
     
     :param selected: Selected video quality measures.
     :type selected: string or list
     :param tuple data: Collected QoS + bit-stream + video parameters.
     """
     Meter.__init__(self)
     VTLOG.info("Starting VQmeter...")
     if 'psnr' in selected:
         self.measures.append(PSNR(data))
     if 'ssim' in selected:
         self.measures.append(SSIM(data))
     if 'g1070' in selected:
         self.measures.append(G1070(data))
     if 'psnrtomos' in selected:
         self.measures.append(PSNRtoMOS(data))
     if 'miv' in selected:
         self.measures.append(MIV(data))
    def __events(self, bus, msg):
        """
		Event handler.
		
		:param bus: Gstreamer bus object.
		:param msg: Gstreamer message object.
		
		:returns: True.
		:rtype: boolean
		"""
        t = msg.type
        if t == MESSAGE_EOS:
            self.pipeline.set_state(STATE_PAUSED)
            sleep(0.5)
            self.pipeline.set_state(STATE_READY)
            self.pipeline.set_state(STATE_NULL)
            VTLOG.debug("GStreamer: MESSAGE_EOS received")
            self.loop.quit()
        elif t == MESSAGE_ERROR:
            self.pipeline.set_state(STATE_PAUSED)
            sleep(0.5)
            self.pipeline.set_state(STATE_READY)
            self.pipeline.set_state(STATE_NULL)
            e, d = msg.parse_error()
            VTLOG.error("GStreamer: MESSAGE_ERROR received")
            VTLOG.error(e)
            self.loop.quit()
        return True
 def __init__(self):
     """
     **On init:** Parse the `video` section.
     
     .. warning::
         This section MUST be present in the default configuration file (see :const:`VideoTester.config.CONF`)
         and MUST contain the same videos at the client and the server.
     
     :raises: Bad configuration file or path.
     """
     from VideoTester.config import CONF
     try:
         #: List of ``(id, name)`` pairs for each available video.
         self.videos = self.parseConf(CONF, "video")
         if self.videos[0][0] != 'path':
             raise
         #: Path to the video directory.
         self.path = self.videos[0][1]
         self.videos.pop(0)
     except:
         VTLOG.error("Bad '" + CONF + "' file or path")
         exit()
Beispiel #17
0
    def __parseUDP(self):
        """
        Parse RTP over UDP session.
        """
        def extract(p):
            """
            Extract information from a UDP packet.
            
            :param Packet p: UDP packet.
            """
            ptype = ord(str(p[UDP].payload)[1]) & 0x7F  #Delete RTP marker
            p[UDP].decode_payload_as(RTP)
            if ptype == self.ptype:
                #Avoid duplicates while running on loopback interface
                if p[RTP].sequence not in self.sequences:
                    self.lengths.append(p.len)
                    self.times.append(p.time)
                    self.sequences.append(p[RTP].sequence + self.__add)
                    self.timestamps.append(p[RTP].timestamp)
                    VTLOG.debug("UDP/RTP packet found. Sequence: " +
                                str(p[RTP].sequence))
                    if p[RTP].sequence == 65535:
                        self.__add += 65536

        play = False
        for p in self.cap:
            if p.haslayer(IP):
                if (str(p).find("PAUSE") != -1) and play:
                    VTLOG.debug("PAUSE found!")
                    break
                if not play:
                    play = self.__prepare(p)
                elif play and (p[IP].src == self.conf['ip']) and (
                        p.haslayer(UDP)) and (str(p).find("GStreamer") == -1):
                    if (p.sport == self.sport) and (p.dport == self.dport):
                        extract(p)
        bubbleSort(self.sequences, self.times, self.timestamps)
        VTLOG.debug("Sequence list sorted")
 def stop(self, bitrate, framerate):
     """
     Stop an RTSP server with a given bitrate and framerate (if no remaining clients)
     or remove a client (if remaining clients).
     
     :param bitrate: The bitrate (in kbps).
     :type bitrate: string or integer
     :param framerate: The framerate (in fps).
     :type framerate: string or integer
     
     :returns: True.
     :rtype: boolean
     """
     key = str(bitrate) + ' kbps - ' + str(framerate) + ' fps'
     self.servers[key]['clients'] = self.servers[key]['clients'] - 1
     if self.servers[key]['clients'] == 0:
         self.servers[key]['server'].terminate()
         self.servers[key]['server'].join()
         VTLOG.info(key + " server: last client disconnected and server stopped")
         self.servers.pop(key)
     else:
         VTLOG.info(key + " server: client disconnected. Remaining: " + str(self.servers[key]['clients']))
     return True
    def reference(self):
        """
		Make the reference videos.
		
		:returns: Paths to video files (see :attr:`files`) and video size (see :attr:`size`).
		:rtype: tuple
		"""
        VTLOG.info("Making reference...")
        self.pipeline = parse_launch(
            'filesrc name=source ! decodebin ! videorate ! video/x-raw-yuv,framerate='
            + self.conf['framerate'] + '/1  ! filesink name=sink1')
        source = self.pipeline.get_by_name('source')
        sink1 = self.pipeline.get_by_name('sink1')
        location = self.video
        self.files['original'].append(location)
        source.props.location = location
        location = self.conf['tempdir'] + self.conf['num'] + '_ref_original.yuv'
        self.files['original'].append(location)
        sink1.props.location = location
        self.__play()
        self.pipeline = parse_launch('filesrc name=source ! decodebin ! videorate ! video/x-raw-yuv,framerate=' + self.conf['framerate'] + '/1  ! ' + self.encoder + ' bitrate=' + self.bitrate \
          + ' ! tee name=t ! queue' + self.__add + ' ! filesink name=sink2 t. ! queue ! decodebin ! filesink name=sink3')
        source = self.pipeline.get_by_name('source')
        sink2 = self.pipeline.get_by_name('sink2')
        sink3 = self.pipeline.get_by_name('sink3')
        location = self.video
        source.props.location = location
        location = self.conf['tempdir'] + self.conf[
            'num'] + '_ref.' + self.conf['codec']
        self.files['coded'].append(location)
        sink2.props.location = location
        location = self.conf['tempdir'] + self.conf['num'] + '_ref.yuv'
        self.files['coded'].append(location)
        sink3.props.location = location
        self.__play()
        VTLOG.info("Reference made")
        return self.files, self.size
 def __init__(self, selected, data):
     """
     **On init:** Register selected QoS measures.
     
     :param selected: Selected QoS measures.
     :type selected: string or list
     :param tuple data: Collected QoS parameters.
     """
     Meter.__init__(self)
     VTLOG.info("Starting QoSmeter...")
     if 'latency' in selected:
         self.measures.append(Latency(data))
     if 'delta' in selected:
         self.measures.append(Delta(data))
     if 'jitter' in selected:
         self.measures.append(Jitter(data))
     if 'skew' in selected:
         self.measures.append(Skew(data))
     if 'bandwidth' in selected:
         self.measures.append(Bandwidth(data))
     if 'plr' in selected:
         self.measures.append(PacketLossRate(data))
     if 'pld' in selected:
         self.measures.append(PacketLossDist(data))
Beispiel #21
0
 def extract(p):
     """
     Extract many RTSP packets from a TCP stream recursively.
     
     :param Packet p: TCP stream.
     """
     fin = False
     a = p[RTSPi].length
     b = p[RTSPi].payload
     c = str(b)[0:a]
     loss = c.find('PACKETLOSS')
     if loss == -1:
         #No loss: look inside then
         ptype = ord(str(
             p[RTSPi].payload)[1]) & 0x7F  #Delete RTP marker
         if ptype == self.ptype:
             aux = str(p).split('ENDOFPACKET')
             p[RTSPi].decode_payload_as(RTP)
             #Avoid duplicates while running on loopback interface
             if p[RTP].sequence not in self.sequences:
                 self.lengths.append(int(aux[2]))
                 self.times.append(float(aux[1]) / 1000000)
                 self.sequences.append(p[RTP].sequence + self.__add)
                 self.timestamps.append(p[RTP].timestamp)
                 VTLOG.debug("TCP/RTP packet found. Sequence: " +
                             str(p[RTP].sequence))
                 if p[RTP].sequence == 65535:
                     self.__add += 65536
     else:
         #Avoid PACKETLOSS
         a = loss + len('PACKETLOSS')
         VTLOG.debug("PACKETLOSS!")
     p = RTSPi(str(b)[a:len(b)])
     ptype = ord(str(p[RTSPi].payload)[1]) & 0x7F
     #Let's find the next RTSP packet
     while not fin and not ((p[RTSPi].magic == 0x24) and
                            (p[RTSPi].channel == 0x00) and
                            (ptype == self.ptype)):
         stream = str(p)
         if stream.find('PACKETLOSS') == 0:
             #Avoid PACKETLOSS
             stream = stream[len('PACKETLOSS'):len(stream)]
             VTLOG.debug("PACKETLOSS!")
         else:
             #Find next packet
             stream = stream[1:len(stream)]
         if len(stream) > 5:
             p = RTSPi(stream)
             ptype = ord(str(p[RTSPi].payload)[1]) & 0x7F
         else:
             #Yep! We're done!
             fin = True
     if not fin:
         extract(p)
Beispiel #22
0
 def parsePkts(self):
     """
     Parse packets and extract :attr:`lengths`, :attr:`times`, :attr:`sequences`, :attr:`timestamps` and :attr:`ping`.
     
     :returns: :attr:`lengths`, :attr:`times`, :attr:`sequences`, :attr:`timestamps` and :attr:`ping`.
     :rtype: tuple
     """
     VTLOG.info("Starting packet parser...")
     if self.conf['protocols'] == "tcp":
         self.__parseTCP()
     else:
         self.__parseUDP()
     self.__normalize()
     a = str(self.sequences[-1] - len(self.sequences) + 1)
     b = str(len(self.sequences))
     VTLOG.debug(b + " RTP packets received, " + a + " losses")
     VTLOG.info("Packet parser stopped")
     return self.lengths, self.times, self.sequences, self.timestamps, self.ping
Beispiel #23
0
 def sniff(count=0, prn=None, lfilter=None, *arg, **karg):
     """
     ``scapy.sendrecv.sniff()`` Scapy function modification. It stops when an RTSP *TEARDOWN* packet is found.
     
     :param integer count: Number of packets to capture (0 means infinite).
     :param prn: Function to apply to each packet. If something is returned, it is displayed.
     :param lfilter: Python function applied to each packet to determine if any further action is requireds.
     
     :returns: A list of packets.
     :rtype: list
     """
     c = 0
     L2socket = conf.L2listen
     s = L2socket(type=ETH_P_ALL, *arg, **karg)
     lst = []
     remain = None
     VTLOG.debug("Sniffer: loop started. Sniffing...")
     while 1:
         sel = select([s], [], [], remain)
         if s in sel[0]:
             p = s.recv(MTU)
             if p is None:
                 break
             #This line fixes the lack of timing accuracy
             p.time = time()
             if lfilter and not lfilter(p):
                 continue
             lst.append(p)
             aux = str(p)
             #Look for a TEARDOWN packet to stop the loop
             if (aux.find("TEARDOWN") != -1) and (aux.find("Public:")
                                                  == -1):
                 VTLOG.debug("TEARDOWN found!")
                 break
             c += 1
             if prn:
                 r = prn(p)
                 if r is not None:
                     print r
             if count > 0 and c >= count:
                 break
     s.close()
     VTLOG.debug("Sniffer: loop terminated")
     return PacketList(lst, "Sniffed")
 def run(self, bitrate, framerate):
     """
     Run a subprocess for an RTSP server with a given bitrate and framerate (if not running)
     or add a client (if running).
     
     :param bitrate: The bitrate (in kbps).
     :type bitrate: string or integer
     :param framerate: The framerate (in fps).
     :type framerate: string or integer
     
     :returns: The RTSP server port.
     :rtype: integer
     
     :raises OSError: An error ocurred while running subprocess.
     """
     from multiprocessing import Process
     from VideoTester.gstreamer import RTSPserver
     key = str(bitrate) + ' kbps - ' + str(framerate) + ' fps'
     if key in self.servers:
         self.servers[key]['clients'] = self.servers[key]['clients'] + 1
     else:
         self.servers[key] = dict()
         while not self.__freePort():
             self.port = self.port + 1
         self.servers[key]['server'] = Process(target=RTSPserver(self.port, bitrate, framerate, self.path, self.videos).run)
         try:
             self.servers[key]['server'].start()
         except e:
             VTLOG.error(e)
             self.servers[key]['server'].terminate()
             self.servers[key]['server'].join()
             exit()
         self.servers[key]['port'] = self.port
         self.servers[key]['clients'] = 1
         VTLOG.info("RTSP Server running!")
     VTLOG.info("PID: " + str(self.servers[key]['server'].pid) + ", " + key + " server, connected clients: " + str(self.servers[key]['clients']))
     return self.servers[key]['port']
    def __init__(self, *args, **kwds):
        VT.__init__(self)
        # begin wxGlade: VTframe.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetIcon(getVTIcon())
        
        # Menu Bar
        self.vtmenubar = wx.MenuBar()
        wxglade_tmp_menu = wx.Menu()
        self.m_files = wxglade_tmp_menu.Append(wx.ID_OPEN, "&Open files...", "Select Pickle files to plot")
        wxglade_tmp_menu.AppendSeparator()
        self.m_exit = wxglade_tmp_menu.Append(wx.ID_EXIT, "E&xit", "Exit program")
        self.vtmenubar.Append(wxglade_tmp_menu, "&File")
        wxglade_tmp_menu = wx.Menu()
        self.m_run = wxglade_tmp_menu.Append(wx.NewId(), "&Run...", "Run test")
        self.vtmenubar.Append(wxglade_tmp_menu, "R&un")
        wxglade_tmp_menu = wx.Menu()
        self.m_about = wxglade_tmp_menu.Append(wx.ID_ABOUT, "&About", "About this program")
        self.vtmenubar.Append(wxglade_tmp_menu, "&Help")
        self.SetMenuBar(self.vtmenubar)
        # Menu Bar end
        self.vtstatusbar = self.CreateStatusBar(1, 0)
        self.tabs = wx.Notebook(self, -1, style=0)
        self.options_tab = wx.Panel(self.tabs, -1)
        self.video_label = wx.StaticText(self.options_tab, -1, "Choose a video:")
        self.video = wx.Choice(self.options_tab, -1, choices=[x[0] for x in self.videos])
        self.codec_label = wx.StaticText(self.options_tab, -1, "Choose a codec:")
        self.codec = wx.Choice(self.options_tab, -1, choices=["h263", "h264", "mpeg4", "theora"])
        self.bitrate_label = wx.StaticText(self.options_tab, -1, "Select the bitrate:")
        self.bitrate = wx.Slider(self.options_tab, -1, 128, 64, 1024, style=wx.SL_HORIZONTAL|wx.SL_LABELS)
        self.framerate_label = wx.StaticText(self.options_tab, -1, "Select the framerate:")
        self.framerate = wx.Slider(self.options_tab, -1, 25, 1, 100, style=wx.SL_HORIZONTAL|wx.SL_LABELS)
        self.sizer_2_staticbox = wx.StaticBox(self.options_tab, -1, "Video options:")
        self.iface_label = wx.StaticText(self.options_tab, -1, "Interface:")
        self.iface = wx.TextCtrl(self.options_tab, -1, "eth0")
        self.ip_label = wx.StaticText(self.options_tab, -1, "Server IP:")
        self.ip = wx.TextCtrl(self.options_tab, -1, "192.168.229.131")
        self.port_label = wx.StaticText(self.options_tab, -1, "Server port:")
        self.port = wx.TextCtrl(self.options_tab, -1, "8000")
        self.protocols = wx.RadioBox(self.options_tab, -1, "Protocol:", choices=["UDP-unicast", "TCP", "UDP-multicast"], majorDimension=3, style=wx.RA_SPECIFY_COLS)
        self.sizer_3_staticbox = wx.StaticBox(self.options_tab, -1, "Net options:")
        self.latency = wx.CheckBox(self.options_tab, -1, "Latency")
        self.delta = wx.CheckBox(self.options_tab, -1, "Delta")
        self.jitter = wx.CheckBox(self.options_tab, -1, "Jitter")
        self.skew = wx.CheckBox(self.options_tab, -1, "Skew")
        self.bandwidth = wx.CheckBox(self.options_tab, -1, "Bandwidth")
        self.plr = wx.CheckBox(self.options_tab, -1, "Packet Loss Rate")
        self.pld = wx.CheckBox(self.options_tab, -1, "Packet Loss Distribution")
        self.sizer_15_staticbox = wx.StaticBox(self.options_tab, -1, "QoS measures:")
        self.seye = wx.CheckBox(self.options_tab, -1, "Stream Eye")
        self.refseye = wx.CheckBox(self.options_tab, -1, "refStream Eye")
        self.gop = wx.CheckBox(self.options_tab, -1, "GOP size")
        self.iflr = wx.CheckBox(self.options_tab, -1, "I Frame Loss Rate")
        self.sizer_16_staticbox = wx.StaticBox(self.options_tab, -1, "BitStream measures:")
        self.psnr = wx.CheckBox(self.options_tab, -1, "PSNR")
        self.ssim = wx.CheckBox(self.options_tab, -1, "SSIM")
        self.g1070 = wx.CheckBox(self.options_tab, -1, "G.1070")
        self.psnrtomos = wx.CheckBox(self.options_tab, -1, "PSNRtoMOS")
        self.miv = wx.CheckBox(self.options_tab, -1, "MIV")
        self.sizer_5_staticbox = wx.StaticBox(self.options_tab, -1, "Video quality measures:")
        self.log_tab = wx.Panel(self.tabs, -1)
        self.log = wx.TextCtrl(self.log_tab, -1, "Log messages:\n----------------\n", style=wx.TE_MULTILINE|wx.TE_READONLY)
        self.results_tab = PlotNotebook(self.tabs)
        self.video_tab = wx.Panel(self.tabs, -1)
        self.label_2 = wx.StaticText(self.video_tab, -1, "Play videos:")
        self.play_video = wx.Button(self.video_tab, -1, "Play", name="playvideo")

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_MENU, self.onOpen, self.m_files)
        self.Bind(wx.EVT_MENU, self.onExit, self.m_exit)
        self.Bind(wx.EVT_MENU, self.onRun, self.m_run)
        self.Bind(wx.EVT_MENU, self.onAbout, self.m_about)
        self.Bind(wx.EVT_CLOSE, self.onCloseWindow)
        self.play_video.Bind(wx.EVT_BUTTON, self.onPlay)
        
        # Logging
        self.log_text = ''
        def update(x):
            self.log_text += x+'\n'
        formatter = logging.Formatter("[%(asctime)s VTClient] %(levelname)s : %(message)s")
        self.hdlr = FuncLog(update)
        self.hdlr.setLevel(logging.DEBUG)
        self.hdlr.setFormatter(formatter)
        VTLOG.addHandler(self.hdlr)
        self.Bind(wx.EVT_IDLE, self.onIdle)
Beispiel #26
0
 def __prepare(self, p):
     """
     Pre-process capture file. This method parses RTSP information and extracts :attr:`ping`, :attr:`ptype` and :attr:`clock`.
     
     :returns: True when a RTSP *PLAY* packet is found.
     :rtype: boolean
     """
     if p.haslayer(ICMP):
         self.ping[p[ICMP].seq][p[ICMP].type] = p.time
     elif str(p).find("Content-Type: application/sdp") != -1:
         lines = str(p[TCP].payload).splitlines()
         for line in lines:
             if line.find("m=video") != -1:
                 fields = line.split(" ")
                 self.ptype = int(fields[-1])
                 VTLOG.debug("Payload type found! Value: " +
                             str(self.ptype))
         for line in lines:
             if line.find("rtpmap:" + str(self.ptype)) != -1:
                 fields = line.split("/")
                 self.clock = int(fields[-1])
                 VTLOG.debug("Clock rate found! Value: " + str(self.clock))
     elif (str(p).find("Transport: RTP") !=
           -1) and (str(p).find('mode="PLAY"') != -1):
         if str(p).find("RTP/AVP/TCP") != -1:
             self.sport = int(p.sport)
             VTLOG.debug("Source port found! Value: " + str(self.sport))
             self.dport = int(p.dport)
             VTLOG.debug("Destination port found! Value: " +
                         str(self.dport))
         else:
             fields = str(p[TCP].payload).split(";")
             for field in fields:
                 if field.find("server_port=") != -1:
                     self.sport = int(field[12:field.index('-')])
                     VTLOG.debug("Source port found! Value: " +
                                 str(self.sport))
                 elif field.find("client_port=") != -1:
                     self.dport = int(field[12:field.index('-')])
                     VTLOG.debug("Destination port found! Value: " +
                                 str(self.dport))
                 elif field.find("port=") != -1:
                     self.sport = int(field[5:field.index('-')])
                     self.dport = self.sport
                     VTLOG.debug("Source/destination port found! Value: " +
                                 str(self.sport))
     elif (str(p).find("PLAY") != -1) and (str(p).find("Public:") == -1):
         self.play = True
         VTLOG.debug("PLAY found!")
     if self.play and self.sport and self.dport:
         play = True
     else:
         play = False
     return play
Beispiel #27
0
    def __parseTCP(self):
        """
        Parse RTP over TCP session.
        """
        def extract(p):
            """
            Extract many RTSP packets from a TCP stream recursively.
            
            :param Packet p: TCP stream.
            """
            fin = False
            a = p[RTSPi].length
            b = p[RTSPi].payload
            c = str(b)[0:a]
            loss = c.find('PACKETLOSS')
            if loss == -1:
                #No loss: look inside then
                ptype = ord(str(
                    p[RTSPi].payload)[1]) & 0x7F  #Delete RTP marker
                if ptype == self.ptype:
                    aux = str(p).split('ENDOFPACKET')
                    p[RTSPi].decode_payload_as(RTP)
                    #Avoid duplicates while running on loopback interface
                    if p[RTP].sequence not in self.sequences:
                        self.lengths.append(int(aux[2]))
                        self.times.append(float(aux[1]) / 1000000)
                        self.sequences.append(p[RTP].sequence + self.__add)
                        self.timestamps.append(p[RTP].timestamp)
                        VTLOG.debug("TCP/RTP packet found. Sequence: " +
                                    str(p[RTP].sequence))
                        if p[RTP].sequence == 65535:
                            self.__add += 65536
            else:
                #Avoid PACKETLOSS
                a = loss + len('PACKETLOSS')
                VTLOG.debug("PACKETLOSS!")
            p = RTSPi(str(b)[a:len(b)])
            ptype = ord(str(p[RTSPi].payload)[1]) & 0x7F
            #Let's find the next RTSP packet
            while not fin and not ((p[RTSPi].magic == 0x24) and
                                   (p[RTSPi].channel == 0x00) and
                                   (ptype == self.ptype)):
                stream = str(p)
                if stream.find('PACKETLOSS') == 0:
                    #Avoid PACKETLOSS
                    stream = stream[len('PACKETLOSS'):len(stream)]
                    VTLOG.debug("PACKETLOSS!")
                else:
                    #Find next packet
                    stream = stream[1:len(stream)]
                if len(stream) > 5:
                    p = RTSPi(stream)
                    ptype = ord(str(p[RTSPi].payload)[1]) & 0x7F
                else:
                    #Yep! We're done!
                    fin = True
            if not fin:
                extract(p)

        def fillGaps(seqlist, lenlist):
            """
            Locate packet losses.
            
            :param list seqlist: List of RTP sequence numbers.
            :param list lenlist: List of packet lengths.
            
            :returns: List of losses (0 -> no loss, 1 -> loss).
            :rtype: list
            """
            fill = [0 for i in range(0, len(seqlist))]
            for i in range(0, len(seqlist) - 1):
                if seqlist[i] + lenlist[i] < seqlist[i + 1]:
                    fill[i] = 1
            return fill

        play = False
        packetlist = []
        seqlist = []
        lenlist = []
        for p in self.cap:
            if p.haslayer(IP):
                if (str(p).find("PAUSE") != -1) and play:
                    VTLOG.debug("PAUSE found!")
                    break
                if not play:
                    play = self.__prepare(p)
                #Packets from server, with TCP layer. Avoid ACK's. Avoid RTSP packets
                elif play and (p[IP].src
                               == self.conf['ip']) and p.haslayer(TCP) and (
                                   len(p) > 66) and (str(p).find("RTSP/1.0")
                                                     == -1):
                    if (p.sport == self.sport) and (p.dport == self.dport):
                        packetlist.append(p)
                        seqlist.append(p[TCP].seq)
                        lenlist.append(len(p[TCP].payload))
                        VTLOG.debug("TCP packet appended. Sequence: " +
                                    str(p[TCP].seq))
        bubbleSort(seqlist, packetlist, lenlist)
        VTLOG.debug("Sequence list sorted")
        #Locate packet losses
        fill = fillGaps(seqlist, lenlist)
        stream = ''
        for i, p in enumerate(packetlist):
            stream = ''.join([stream, str(p[TCP].payload)])
            #Mark ENDOFPACKET and save time and length
            stream = ''.join([stream, 'ENDOFPACKET'])
            stream = ''.join([stream, str(int(p.time * 1000000))])
            stream = ''.join([stream, 'ENDOFPACKET'])
            stream = ''.join([stream, str(p.len)])
            stream = ''.join([stream, 'ENDOFPACKET'])
            if fill[i]:
                #Mark PACKETLOSS
                VTLOG.debug("PACKETLOSS!")
                stream = ''.join([stream, 'PACKETLOSS'])
        VTLOG.debug("TCP payloads assembled")
        stream = RTSPi(stream)
        extract(stream)
 def run(self):
     """
     Run the client and perform all the operations:
      * Connect to the server.
      * Receive video while sniffing packets.
      * Close connection.
      * Process data and extract information.
      * Run meters.
     
     :returns: A list of measures (see :attr:`VideoTester.measures.core.Meter.measures`) and the path to the temporary directory plus files prefix: ``<path-to-tempdir>/<prefix>``.
     :rtype: tuple
     """
     VTLOG.info("Client running!")
     VTLOG.info("XMLRPC Server at " + self.conf['ip'] + ':' + self.conf['port'])
     VTLOG.info("Evaluating: " + self.conf['video'] + " + " + self.conf['codec'] + " at " + self.conf['bitrate'] + " kbps and " + self.conf['framerate'] + " fps under " + self.conf['protocols'])
     from xmlrpclib import ServerProxy
     from scapy.all import rdpcap
     from multiprocessing import Process, Queue
     from VideoTester.gstreamer import RTSPclient
     from VideoTester.sniffer import Sniffer
     from VideoTester.measures.qos import QoSmeter
     from VideoTester.measures.bs import BSmeter
     from VideoTester.measures.vq import VQmeter
     try:
         server = ServerProxy('http://' + self.conf['ip'] + ':' + self.conf['port'])
         self.conf['rtspport'] = str(server.run(self.conf['bitrate'], self.conf['framerate']))
     except:
         VTLOG.error("Bad IP or port")
         exit()
     sniffer = Sniffer(self.conf)
     rtspclient = RTSPclient(self.conf, self.video)
     q = Queue()
     child = Process(target=sniffer.run, args=(q,))
     try:
         child.start()
         self.__ping()
         rtspclient.receiver()
         sniffer.cap = rdpcap(q.get())
         child.join()
     except KeyboardInterrupt:
         VTLOG.warning("Keyboard interrupt!")
         server.stop(self.conf['bitrate'], self.conf['framerate'])
         child.terminate()
         child.join()
         exit()
     server.stop(self.conf['bitrate'], self.conf['framerate'])
     videodata, size = rtspclient.reference()
     conf = {'codec':self.conf['codec'], 'bitrate':float(self.conf['bitrate']), 'framerate':float(self.conf['framerate']), 'size':size}
     packetdata = sniffer.parsePkts()
     codecdata, rawdata = self.__loadData(videodata, size, self.conf['codec'])
     qosm = QoSmeter(self.conf['qos'], packetdata).run()
     bsm = BSmeter(self.conf['bs'], codecdata).run()
     vqm = VQmeter(self.conf['vq'], (conf, rawdata, codecdata, packetdata)).run()
     self.__saveMeasures(qosm + bsm + vqm)
     VTLOG.info("Client stopped!")
     return qosm + bsm + vqm, self.conf['tempdir'] + self.conf['num']