class FLVPlayer(Player): """ Reads a FLV stream and emulates playout by advancing the stream as time passes """ FILE_HEADER_SIZE = 9 TAG_HEADER_SIZE = 15 def __init__(self): Player.__init__(self) self._lastAudioTS = 0 self._lastVideoTS = 0 self.flv = FLV(self) def feed(self, data): """ input downloaded media data here piece by piece """ self.put(data) # nothing parsed yet if self.tell() == 0: self.changeState(PlayerState.BUFFERING) if self.availBytes() >= self.FILE_HEADER_SIZE: self.flv.parse_header() else: tag = 0 while tag != None: avail = self.availBytes() tag = None if avail >= self.TAG_HEADER_SIZE: # peek for tag size tag_type = get_ui8(self) tag_size = get_ui24(self) # log.debug("peek: %02X %u, available: %u" % (tag_type,tag_size,avail)) self.seek(-4, os.SEEK_CUR) # size + next header size if avail >= tag_size + self.TAG_HEADER_SIZE: tag = self.flv.get_next_tag() if type(tag) == VideoTag: self._lastVideoTS = tag.timestamp # log.debug("lastVideo: %u", self._lastVideoTS) elif type(tag) == AudioTag: self._lastAudioTS = tag.timestamp # log.debug("lastAudio: %u", self._lastAudioTS) super(FLVPlayer, self).feed(data) def getLastMediaTimeStamp(self): """ get the presentation TS of the last complete frame """ raise NotImplementedException() return min(self._lastVideoTS, self._lastAudioTS) / 1000.0 def getBufferedSeconds(self, offset = 0): """ until when the buffer contains media """ return (min(self._lastVideoTS, self._lastAudioTS) / 1000.0) - offset def __str__(self): return ' FLVPlayer(unparsed bytes: %d, last A/V TS: %u/%u)' % \ (self.availBytes(), self._lastAudioTS, self._lastVideoTS)