wiki:GEC16Agenda/WiMAX-Tutorial/Streamload/02

Version 4 (modified by Fraida Fund, 11 years ago) (diff)

--

Previous

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.


Next