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 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 __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()
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, 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 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 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)
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
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)
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']
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 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
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
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
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 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 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 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, 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))