Instrumenting with OML
After verifying that the simple streamload client works as expected, the experimenter followed the instructions given on the oml4py library homepage to instrument the script. The experimenter set up three measurement points (database tables) in the script:
- conf - at initialization, the client reports its own configuration settings
- dl - the client reports the chunk number and layer number each time a subchunk is downloaded
- play - the client reports the chunk number and the cumulative number of layers that are played each time a chunk is played
#!/usr/bin/python import sys, time, httplib2, math, thread, oml4py from xml.dom.minidom import parse, parseString from optparse import OptionParser class Finished(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class Wait(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class StreamLoad: def __init__(self): self.oml = oml4py.OMLBase("streamload") self.oml.addmp("dl", "chunk:long layer:long") self.oml.addmp("conf", "key:string value:string") self.oml.addmp("play", "chunk:long layers:long") def getConfig(self, baseurl, video): self.video = video resp, content = httplib2.Http().request(baseurl + video + ".xml") doc = parseString(content) for node in doc.getElementsByTagName('video'): self.buf = int(node.attributes["buffer"].value) self.chunks = int(node.attributes["chunks"].value) self.layers = int(node.attributes["layers"].value) self.urlbase = str(baseurl) + str(node.attributes["url"].value) self.chunktime = float(node.attributes["chunktime"].value) def player(self): startbuf = 0 self.played = 0 start = self.starttime while self.played<self.chunks: thistime = time.time() if thistime-start >= self.chunktime and self.downloaded[0]>self.played: maxlayer = -1 for i in range(self.layers): if self.downloaded[i]>=self.played+1: maxlayer = i self.oml.inject("play", [self.played+1, maxlayer]) self.played+=1 start = thistime time.sleep(0.001) def start(self, window, sl): self.sl=sl if self.sl: self.window = int(window) else: self.window = int(self.buf) self.oml.start() self.oml.inject("conf", ["video", str(self.video)]) self.oml.inject("conf", ["chunks", str(self.chunks)]) self.oml.inject("conf", ["layers", str(self.layers)]) self.oml.inject("conf", ["chunktime", str(self.chunktime)]) self.oml.inject("conf", ["buffer", str(self.buf)]) self.oml.inject("conf", ["window", str(self.window)]) self.oml.inject("conf", ["url", str(self.urlbase)]) self.oml.inject("conf", ["sl", str(sl)]) self.downloaded = {} for i in range(self.layers): self.downloaded[i] = 0 self.played = 0 self.starttime = 0 self.getNextPiece() self.starttime = time.time() self.t = thread.start_new_thread(self.player,()) while True: try: self.getNextPiece() except Wait: pass def nextUp(self): # Return chunk 1, layer 0 if we haven't downloaded anything yet if self.starttime == 0: return(1,0) base_chunks_played = self.played if base_chunks_played == self.chunks: raise Finished("all done here") # Download base layer if we are allowed to if (self.downloaded[0] - base_chunks_played) < self.buf and (self.downloaded[0] + 1) <= self.chunks: return (self.downloaded[0]+1,0) else: for i in range(self.layers-1): i = i+1 tmp = max(self.downloaded[i],base_chunks_played+1) # If it's in the window and not past the end of the video, download it if tmp - base_chunks_played <= self.window and tmp + 1 <= self.chunks: return (tmp + 1,i) # After all subchunks in the quality windows are downloaded, request one chunk at a time, lower layers first for i in range(self.layers-1): i = i + 1 # If I am the highest layer and I have less than the layer beneath me, get the next chunk in my layer if self.sl and i == self.layers-1 and self.downloaded[i] <= self.downloaded[i-1] and self.downloaded[i]+1<=self.chunks: return (self.downloaded[i]+1,i) # Otherwise, if I have less than or the same as the layer above me, download the next chunk if self.sl and i < self.layers-1 and self.downloaded[i] <= self.downloaded[i+1] and self.downloaded[i]+1<=self.chunks: return (self.downloaded[i]+1,i) raise Wait("Nothing to do") def getNextPiece(self): try: (chunk, layer) = self.nextUp() except Wait: return nxt = "chunk" + str(chunk) + "_" + str(layer) + ".264" try: resp, content = httplib2.Http().request(self.urlbase + nxt) except: print "Error downloading file" if chunk > self.played or chunk==self.chunks: try: self.lastpiecetime = time.time() self.oml.inject("dl", [chunk, layer]) except: return self.downloaded[layer] = chunk if __name__ == "__main__": parser = OptionParser() parser.add_option("-u", "--url", dest="url", help="URL of video source") parser.add_option("-v", "--video", dest="video", help="Name of video") parser.add_option("-w", "--window", dest="window", default="5", help="Download window for enhancement layers") parser.add_option("-s", "--streamload", dest = "sl", default="True", help="Download in streamload mode") (options, args) = parser.parse_args() x = StreamLoad() x.getConfig(options.url,options.video) try: if options.sl == "True": x.start(int(options.window),True) else: x.start(int(options.window),False) except Finished: sys.exit(0)
Note: In addition to the oml4py module for Python, there is also the oml4r gem for instrumenting Python applications, and a C library for C/C++ applications. There is also a text protocol which can be used with any language.
Last modified 11 years ago
Last modified on 03/19/13 15:38:18