From 5f31332cd383c72f598190f90efd9ab7c96bfdb2 Mon Sep 17 00:00:00 2001 From: matt Date: Mon, 29 Jun 2009 09:44:49 +1200 Subject: [PATCH] Added semi working THP player, has experimental frame skipping code, but is still in need of math checks as it is currently out of time after a while, no AUDIO, but there is video. Sadly python is a bit slow. --- thp.py | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 thp.py diff --git a/thp.py b/thp.py new file mode 100644 index 0000000..f05abc0 --- /dev/null +++ b/thp.py @@ -0,0 +1,182 @@ +from Struct import * +from pyglet import clock, window, image +from pyglet.gl import * +import cStringIO +import math + +from time import time + + +class THP(): + class THPHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.string(4) + self.version = Struct.uint32 + self.bufSize = Struct.uint32 + self.audioMaxSamples = Struct.uint32 + self.frameRate = Struct.float + self.numFrames = Struct.uint32 + self.firstFrameSize = Struct.uint32 + self.movieDataSize = Struct.uint32 + self.compInfoDataOffsets = Struct.uint32 + self.offsetDataOffsets = Struct.uint32 #Offset to a offset table, containing offsets to each frame, this allows for starting playback from any frame. If this is 0 then it does not exist. + self.movieDataOffsets = Struct.uint32 + self.finalFrameDataOffsets = Struct.uint32 + def __str__(self): + ret = "\n" + ret += "Magic: %s\n" % self.magic + ret += "Version: %d.%d.%d\n" % (((self.version & 0xFFFF0000) >> 16), ((self.version & 0xFF00) >> 8), ((self.version & 0xFF))) + ret += "bufSize: %s\n" % self.bufSize + ret += "audioMaxSamples: %d\n" % self.audioMaxSamples + ret += "frameRate: %f\n" % self.frameRate + ret += "numFrames: %d\n" % self.numFrames + ret += "firstFrameSize: %d\n" % self.firstFrameSize + ret += "movieDataSize: %d\n" % self.movieDataSize + ret += "compInfoDataOffsets: 0x%08X\n" % self.compInfoDataOffsets + ret += "offsetDataOffsets: 0x%08X\n" % self.offsetDataOffsets + ret += "movieDataOffsets: 0x%08X\n" % self.movieDataOffsets + ret += "finalFrameDataOffsets: 0x%08X\n" % self.finalFrameDataOffsets + return ret + class THPFrameCompInfo(Struct): + __endian__ = Struct.BE + def __format__(self): + self.numComponents = Struct.uint32 + self.frameComp = Struct.uint8[16] + def __str__(self): + ret = "" + ret += "Number of Components: %d\n" % self.numComponents + return ret + class THPCompVideoInfo(Struct): + __endian__ = Struct.BE + def __format__(self): + self.width = Struct.uint32 + self.height = Struct.uint32 + self.videoType = Struct.uint32 + def __str__(self): + tempType = ("Non-Interlaced", "Interlaced", "Odd Interlace", "3", "Even Interlace") + ret = "" + ret += "Width: %d\n" % self.width + ret += "Height: %d\n" % self.height + ret += "VideoType: %s\n" % tempType[self.videoType] + return ret + class THPCompAudioInfo(Struct): + __endian__ = Struct.BE + def __format__(self): + self.sndChannels = Struct.uint32 + self.sndFrequency = Struct.uint32 + self.sndNumberSamples = Struct.uint32 + self.sndNumberTracks = Struct.uint32 + def __str__(self): + ret = "" + ret += "Channels: %d\n" % self.sndChannels + ret += "Frequency: %d\n" % self.sndFrequency + ret += "Samples: %d\n" % self.sndNumberSamples + ret += "Tracks: %d\n" % self.sndNumberTracks + return ret + class THPFrameHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.frameSizeNext = Struct.uint32 + self.frameSizePrev = Struct.uint32 + self.vidFileSize = Struct.uint32 + self.sndFileSize = Struct.uint32 + def __str__(self): + ret = "" + ret += "next Frame Size: %d\n" % self.frameSizeNext + ret += "previous Frame Size: %d\n" % self.frameSizePrev + ret += "Video frame data size: %d\n" % self.vidFileSize + ret += "Track file size: %d\n" % self.sndFileSize + return ret + def readData(self, fp, i=0): + self.frameImage = fp.read(self.vidFileSize) + #fileName = "frame%06d.jpg" % i + #open("out/" + fileName, 'w+b').write(self.frameImage) + #print "Frame: %d" % i + startTime = time() + start = self.frameImage.find('\xff\xda') + end = self.frameImage.rfind('\xff\xd9') + #print "find(%d): This took "%i, time()-startTime,start,end + startTime = time() + startStr = self.frameImage[:start+2] + endStr = self.frameImage[end:] + #print "extr(%d): This took "%i, time()-startTime + self.frameImage = self.frameImage[start+2:end] + self.frameImage = startStr + self.frameImage.replace('\xff','\xff\x00') + endStr + #print self.frameImage + + + return cStringIO.StringIO(self.frameImage) + def __init__(self, movieFile=None): + if(movieFile==None): + print "Usage: python thp.py filename.thp" + exit(-1) + fp = file(movieFile, 'rb') + HEADER = self.THPHeader() + HEADER.unpack(fp.read(len(HEADER))) + print HEADER + fp.seek(HEADER.compInfoDataOffsets) + CompInfo = self.THPFrameCompInfo() + CompInfo.unpack(fp.read(len(CompInfo))) + print CompInfo + for i in range(0, CompInfo.numComponents): + if(CompInfo.frameComp[i] == 0): + VideoInfo = self.THPCompVideoInfo() + VideoInfo.unpack(fp.read(len(VideoInfo))) + print VideoInfo + if(CompInfo.frameComp[i] == 1): + AudioInfo = self.THPCompAudioInfo() + AudioInfo.unpack(fp.read(len(AudioInfo))) + print AudioInfo + + clock.set_fps_limit(HEADER.frameRate) + currOff = HEADER.movieDataOffsets + currSize = HEADER.firstFrameSize + fp.seek(currOff) + + win = window.Window(VideoInfo.width, VideoInfo.height) + fps_display = clock.ClockDisplay() + i = 1 + j = 1 + image_index = 0 + image_period = 1.0 / HEADER.frameRate # Reciprocal of the frame rate + remained = 0 + + while not win.has_exit: + + win.dispatch_events() + win.clear() + + dt = clock.tick() + + skip = math.floor((dt+remained)/image_period) + j += skip + print skip, ":break:", i, j, skip + remained = dt - skip * image_period + + tempFrame = self.THPFrameHeader() + tempFrame.unpack(fp.read(len(tempFrame))) + + for xx in range(1,skip): + currOff = currOff+currSize + currSize = tempFrame.frameSizeNext + fp.seek(currOff) + tempFrame = self.THPFrameHeader() + tempFrame.unpack(fp.read(len(tempFrame))) + + imagedat = tempFrame.readData(fp, i) + + pic = image.load("image.jpg",imagedat) + pic.blit(0,0) + + currOff = currOff+currSize + currSize = tempFrame.frameSizeNext + fp.seek(currOff) + + + fps_display.draw() + win.flip() + i += 1 + +if __name__=='__main__': + THP(*sys.argv[1:]) \ No newline at end of file