#!/usr/bin/env python # Copyright 2006 John-Mark Gurney '''MPEG-TS Handling''' __version__ = '$Change$' # $Id$ default_audio_lang = 'eng' import os import sets import sys mpegtspath = '/Users/jgurney/p4/bktrau/info' if mpegtspath not in sys.path: sys.path.append(mpegtspath) import mpegts from DIDLLite import StorageFolder, VideoItem, Resource from FSStorage import FSObject, registerklassfun from twisted.python import log, threadable from twisted.spread import pb from twisted.web import resource, server class _LimitedFile(file): def __init__(self, *args, **kwargs): self.__size = kwargs['size'] del kwargs['size'] file.__init__(self, *args, **kwargs) def remain(self): pos = self.tell() if pos > self.__size: return 0 return self.__size - pos def read(self, size=-1): if size < 0: return file.read(self, self.remain()) return file.read(self, min(size, self.remain())) def _gennameindexes(chan): ret = [] d = {} for i in chan: t = '%s %s.%s' % (i['name'], i['major'], i['minor']) ret.append(t) d[t] = i return ret, d class MPEGTSTransfer(pb.Viewable): def __init__(self, iterable, request): self.iter = iter(iterable) self.request = request request.registerProducer(self, 0) def resumeProducing(self): if not self.request: return # get data and write to request. try: data = self.iter.next() if data: # this .write will spin the reactor, calling # .doWrite and then .resumeProducing again, so # be prepared for a re-entrant call self.request.write(data) except StopIteration: if self.request: self.request.unregisterProducer() self.request.finish() self.request = None def pauseProducing(self): pass def stopProducing(self): # close zipfile self.request = None # Remotely relay producer interface. def view_resumeProducing(self, issuer): self.resumeProducing() def view_pauseProducing(self, issuer): self.pauseProducing() def view_stopProducing(self, issuer): self.stopProducing() synchronized = ['resumeProducing', 'stopProducing'] threadable.synchronize(MPEGTSTransfer) class MPEGTSResource(resource.Resource): isLeaf = True def __init__(self, iter_): resource.Resource.__init__(self) self.iter = iter_ def render(self, request): request.setHeader('content-type', 'video/mpeg') if request.method == 'HEAD': return '' # return data MPEGTSTransfer(self.iter, request) # and make sure the connection doesn't get closed return server.NOT_DONE_YET class MPEGTS(FSObject, VideoItem): def __init__(self, *args, **kwargs): path = kwargs['path'] del kwargs['path'] self.tvct = kwargs['tvct'] del kwargs['tvct'] kwargs['content'] = MPEGTSResource( mpegts.iteravpids(mpegts.TSPStream(open(path)), sum(mpegts.getaudiovideopids(self.tvct['PMT']), []))) VideoItem.__init__(self, *args, **kwargs) FSObject.__init__(self, path) self.url = '%s/%s' % (self.cd.urlbase, self.id) self.res = Resource(self.url, 'http-get:*:video/mpeg:*') def doUpdate(self): pass class MultiMPEGTS(FSObject, StorageFolder): def __init__(self, *args, **kwargs): path = kwargs['path'] del kwargs['path'] StorageFolder.__init__(self, *args, **kwargs) FSObject.__init__(self, path) # mapping from path to objectID self.pathObjmap = {} def doUpdate(self): f = mpegts.TSPStream(_LimitedFile(self.FSpath, size= 2*1024*1024)) self.tvct = mpegts.GetTVCT(f) doupdate = False origchildren, toindex = _gennameindexes(self.tvct['channels']) children = sets.Set(origchildren) for i in self.pathObjmap.keys(): if i not in children: doupdate = True # delete self.cd.delItem(self.pathObjmap[i]) del self.pathObjmap[i] for i in origchildren: if i in self.pathObjmap: continue # new object self.pathObjmap[i] = self.cd.addItem(self.id, MPEGTS, i, path = self.FSpath, tvct = toindex[i]) doupdate = True if doupdate: StorageFolder.doUpdate(self) def detectmpegts(path, fobj): f = mpegts.TSPStream(_LimitedFile(path, size= 2*1024*1024)) tvct = mpegts.GetTVCT(f) if len(tvct['channels']) == 1: return None, None # We might reenable this once we have pid filtering working # fast enough. #return MPEGTS, { 'path': path, 'tvct': tvct['channels'][0] } elif len(tvct['channels']) > 1: return MultiMPEGTS, { 'path': path } return None, None registerklassfun(detectmpegts)