wiki:GEC16Agenda/WiMAX-Tutorial/Streamload/02

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

--

After verifying that the simple streamload client works as expected, the experimenter uses the oml4py library to instrument the script. The experimenter set up three measurement points 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)