Add even more of the source
This should be about everything needed to build so far?
This commit is contained in:
parent
af3619d4fa
commit
849723c9cf
547 changed files with 149239 additions and 0 deletions
203
StreamingLoadTool/parseSLTOut.py
Normal file
203
StreamingLoadTool/parseSLTOut.py
Normal file
|
@ -0,0 +1,203 @@
|
|||
#!python
|
||||
|
||||
"""Script for parsing the output of a StreamingLoadTool file. Can be used both as a script and as a python module.
|
||||
The output is a commma separated file. The StreamingLoadTool has to be run with -V 3 or above.
|
||||
|
||||
Usage: ParseSLTOut.py [-h] [-b interval] [-s all] [filename]
|
||||
|
||||
options:
|
||||
-h show this help message and exit
|
||||
-b Take the packet lengths and categorizes them according to their arrival time.
|
||||
The packet lengths within the same bucket (of size interval seconds) are summed up
|
||||
and averaged over the interval, which is useful for seeing the bit rate.
|
||||
-s The streams to parse: one of video, audio, all; default is video
|
||||
|
||||
If filename is missing, then the script will read from standard in. The script writes to standard out."""
|
||||
|
||||
"""
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*
|
||||
"""
|
||||
|
||||
import re, sys
|
||||
|
||||
#the regular expression for matching lines in the SLT output
|
||||
playRE = re.compile(\
|
||||
r"^Receiving track (\d+), trackID=(\d+), (\w+) at time (\d+)")
|
||||
timeRE = re.compile(\
|
||||
r"^Processing incoming packets at time (\d+)")
|
||||
processedRE = re.compile(\
|
||||
r"^Processed packet: track=(\d+), len=(\d+), seq=(\d+), time=(\d+)\((\d+)\); bufferingDelay=(\d+), FBS=(\d+)")
|
||||
|
||||
|
||||
def parseSLTInput(inputFile):
|
||||
"""
|
||||
Parses a string consisting of outputs from StreamingLoadTool.
|
||||
The output is a list, where the index is the track index. The value is a map that maps from processing time to
|
||||
packets. Each packet is a 3-tuple containing the packet length(in bytes), the sequence number, and the timestamp.
|
||||
"""
|
||||
videoTrackIndex = None
|
||||
audioTrackIndex = None
|
||||
localTimeBase = None
|
||||
curTime = None
|
||||
|
||||
packetTable = [{}, {}]
|
||||
|
||||
for line in inputFile:
|
||||
matchObj = playRE.match(line)
|
||||
if matchObj is not None:
|
||||
trackIndex, trackID, trackType, startTime = matchObj.groups();
|
||||
if trackType == "video":
|
||||
videoTrackIndex = int(trackIndex)
|
||||
elif trackType == "audio":
|
||||
audioTrackIndex = int(trackIndex)
|
||||
localTimeBase = int(startTime)
|
||||
continue
|
||||
|
||||
matchObj = timeRE.match(line)
|
||||
if matchObj is not None:
|
||||
processingTime, = matchObj.groups()
|
||||
curTime = int(processingTime)
|
||||
continue
|
||||
|
||||
matchObj = processedRE.match(line)
|
||||
if matchObj is not None:
|
||||
trackIndex, packetLen, seqNum, timeStamp, timeStampInMediaTime, playoutDelay, freeBufferSpace = matchObj.groups()
|
||||
trackIndex = int(trackIndex);
|
||||
while trackIndex >= len(packetTable):
|
||||
packetTable.append({})
|
||||
packetList = packetTable[trackIndex].setdefault(curTime, [])
|
||||
packetList.append( (int(packetLen), int(seqNum), int(timeStamp)) )
|
||||
continue
|
||||
|
||||
if localTimeBase is None:
|
||||
sys.exit("Parse error: cannot find a track")
|
||||
|
||||
# modify the processing times to be 0-based
|
||||
newPacketTable = [{}] * len(packetTable)
|
||||
for trackIndex in range(len(packetTable)):
|
||||
newPackets = {}
|
||||
for (curTime, packet) in packetTable[trackIndex].items():
|
||||
curTime -= localTimeBase
|
||||
newPackets[curTime] = packet
|
||||
packetTable[trackIndex] = newPackets
|
||||
|
||||
return (packetTable, videoTrackIndex, audioTrackIndex)
|
||||
|
||||
|
||||
def calcBitRate(xList, yList, interval):
|
||||
"""xList is a list of processing time, and yList is a list of packet size.
|
||||
The function will calculate the bitrate, divided into interval-sized buckets, and returns it as a list
|
||||
of (processing time, bitrate) pair.
|
||||
xList is expected to be a list of time in milliseconds, and yList is expected to be a list of packet size in bytes."""
|
||||
maxIndex = max(xList) / interval
|
||||
bitsReceived = [0] * (maxIndex + 1)
|
||||
|
||||
for i in range(len(yList)):
|
||||
x = xList[i]
|
||||
y = yList[i]
|
||||
|
||||
bitsReceived[x / interval] += y * 8
|
||||
|
||||
return [ (i * interval, (bitsReceived[i] * 1000) / interval) for i in range(len(bitsReceived))]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# the file is ran as a script
|
||||
|
||||
# first parse the command line
|
||||
import getopt
|
||||
from decimal import Decimal
|
||||
|
||||
try:
|
||||
optlist, args = getopt.getopt(sys.argv[1:], "hb:s:")
|
||||
except getopt.GetoptError:
|
||||
sys.exit(__doc__)
|
||||
|
||||
categorize = False
|
||||
streams = 'video'
|
||||
for opt, optarg in optlist:
|
||||
if opt == '-h':
|
||||
print __doc__
|
||||
sys.exit(0)
|
||||
elif opt == '-b':
|
||||
categorize = True
|
||||
try:
|
||||
interval = int(Decimal(optarg) * 1000)
|
||||
except:
|
||||
sys.exit(__doc__)
|
||||
elif opt == '-s':
|
||||
streams = optarg
|
||||
if streams != 'video' and streams != 'audio' and streams != 'all':
|
||||
sys.exit(__doc__)
|
||||
|
||||
if len(args) == 0:
|
||||
inputFile = sys.stdin
|
||||
elif len(args) == 1:
|
||||
inputFile = open(args[0], 'r')
|
||||
else:
|
||||
sys.exit(__doc__)
|
||||
|
||||
(packetTable, videoIndex, audioIndex) = parseSLTInput(inputFile)
|
||||
|
||||
if streams == 'video':
|
||||
if videoIndex is None:
|
||||
sys.exit("Parse error: Cannot find a video stream")
|
||||
packets = packetTable[videoIndex]
|
||||
elif streams == 'audio':
|
||||
if audioIndex is None:
|
||||
sys.exit("Parse error: Cannot find an audio stream")
|
||||
packets = packetTable[audioIndex]
|
||||
else:
|
||||
packets = {}
|
||||
for perStreamPackets in packetTable:
|
||||
for (time, packetList) in perStreamPackets.items():
|
||||
packets.setdefault(time, []).extend(packetList)
|
||||
|
||||
if len(packets) == 0:
|
||||
sys.exit("Error: Cannot find a stream")
|
||||
|
||||
|
||||
def millisecondsToSec(time):
|
||||
"""Convert time to 123.456 form as a string"""
|
||||
return str(time / 1000) + '.' + str(time % 1000)
|
||||
|
||||
if categorize:
|
||||
xList = []
|
||||
yList = []
|
||||
|
||||
for processingTime, packetList in packets.items():
|
||||
for (packetLen, seqNum, timeStamp) in packetList:
|
||||
xList.append(processingTime)
|
||||
yList.append(packetLen)
|
||||
data = calcBitRate(xList, yList, interval)
|
||||
for (time, bitrate) in data:
|
||||
print "%s, %i" % (millisecondsToSec(time), bitrate)
|
||||
else:
|
||||
processingTimes = packets.keys()
|
||||
processingTimes.sort()
|
||||
for processingTime in processingTimes:
|
||||
packetList = packets[processingTime]
|
||||
for (packetLen, seqNum, timeStamp) in packets[processingTime]:
|
||||
# output.append( (processingTime, packetLen) )
|
||||
print ("%s, %i") % ( millisecondsToSec(processingTime), packetLen )
|
Loading…
Add table
Add a link
Reference in a new issue