document DMC-250 and add it to the QA check list... [git-p4: depot-paths = "//depot/": change = 1347]main
| @@ -0,0 +1,115 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright 2009 John-Mark Gurney <jmg@funkthat.com> | |||||
| '''MPEG-TS clip''' | |||||
| __version__ = '$Change: 1308 $' | |||||
| # $Id: //depot/python/pymeds/main/shoutcast.py#22 $ | |||||
| import bisect | |||||
| import email | |||||
| import os.path | |||||
| from DIDLLite import VideoItem, Resource | |||||
| from FSStorage import registerklassfun | |||||
| from twisted.web import static | |||||
| class ClipProxyFile: | |||||
| def __init__(self, f, p): | |||||
| self.fp = open(f) | |||||
| self.p = p | |||||
| self.pos = 0 | |||||
| lp = p[-1] | |||||
| self.size = lp[0] + lp[1] | |||||
| def read(self, s=None): | |||||
| if s is None: | |||||
| s = self.size - self.pos | |||||
| p = bisect.bisect_right(self.p, (self.pos,)) | |||||
| if p > 0: | |||||
| p -= 1 | |||||
| # We might be able to do this with proper construction of | |||||
| # self.p, but this is easier. | |||||
| r = [] | |||||
| fp = self.fp | |||||
| records = iter(self.p[p:]) | |||||
| while s: | |||||
| rec = records.next() | |||||
| diff = self.pos - rec[0] | |||||
| rlen = min(s, rec[1] - diff) | |||||
| fp.seek(rec[2] + diff) | |||||
| r.append(fp.read(rlen)) | |||||
| s -= rlen | |||||
| self.pos += rlen | |||||
| return ''.join(r) | |||||
| def close(self): | |||||
| self.fp.close() | |||||
| def seek(self, p, d=0): | |||||
| assert d == 0 | |||||
| self.pos = p | |||||
| if self.pos > self.size: | |||||
| self.pos = self.size | |||||
| def tell(self): | |||||
| return self.pos | |||||
| class ClipProxy(static.File): | |||||
| isLeaf = True | |||||
| synchronized = [ 'parsefile', 'getsize', 'open' ] | |||||
| def __init__(self, f, *args): | |||||
| self.__mtime = None | |||||
| static.File.__init__(self, f, *args) | |||||
| self.parsefile(self.path) | |||||
| def parsefile(self, f): | |||||
| if self.getModificationTime() == self.__mtime: | |||||
| return | |||||
| self.__mtime = self.getModificationTime() | |||||
| i = email.message_from_file(open(f)) | |||||
| self.origfile = i['file'] | |||||
| self.date = eval(i['datetuple'], { '__builtins__': {} }) | |||||
| # date is UTC | |||||
| p = [ map(int, x.split()) for x in i.get_payload().split('\n') if x ] | |||||
| pos = 0 | |||||
| self.pos = par = [] | |||||
| for j in p: | |||||
| l = j[1] - j[0] + 188 | |||||
| par.append((pos, l, j[0])) | |||||
| pos += l | |||||
| self.__size = pos | |||||
| def getsize(self): | |||||
| return self.__size | |||||
| def open(self): | |||||
| return ClipProxyFile(self.origfile, self.pos) | |||||
| def restat(self): | |||||
| static.File.restat(self) | |||||
| self.parsefile(self.path) | |||||
| class ClipFile(VideoItem): | |||||
| def __init__(self, *args, **kwargs): | |||||
| file = kwargs.pop('file') | |||||
| mimetype = 'video/mpeg' | |||||
| kwargs['content'] = ClipProxy(file, mimetype) | |||||
| VideoItem.__init__(self, *args, **kwargs) | |||||
| self.url = '%s/%s' % (self.cd.urlbase, self.id) | |||||
| self.res = Resource(self.url, 'http-get:*:%s:*' % mimetype) | |||||
| def detectclipfile(origpath, fobj): | |||||
| path = os.path.basename(origpath) | |||||
| ext = os.path.splitext(path)[1] | |||||
| if ext == '.clip': | |||||
| return ClipFile, { 'file': origpath } | |||||
| return None, None | |||||
| registerklassfun(detectclipfile) | |||||
| @@ -1,7 +1,7 @@ | |||||
| General Functionality | General Functionality | ||||
| error w/o media dir | error w/o media dir | ||||
| PS3 DSM-520 Cidero Intel | |||||
| PS3 DSM-520 Cidero Intel DMC-250 | |||||
| Discovered | Discovered | ||||
| remains after 30m | remains after 30m | ||||
| FSStorage | FSStorage | ||||
| @@ -12,3 +12,5 @@ mpegtsmod | |||||
| shoutcast | shoutcast | ||||
| dvd | dvd | ||||
| pyvr | pyvr | ||||
| Clip | |||||
| item | |||||
| @@ -14,6 +14,7 @@ Tested basic functionality with the following devices and/or programs: | |||||
| Intel's Media Control Point and Media Renderer | Intel's Media Control Point and Media Renderer | ||||
| D-Link DSM-520 | D-Link DSM-520 | ||||
| Sony PlayStation 3 | Sony PlayStation 3 | ||||
| Linksys DMC-250 | |||||
| The Intel tools are good for testing (though Windows only) and are | The Intel tools are good for testing (though Windows only) and are | ||||
| available at: | available at: | ||||
| @@ -82,7 +83,7 @@ v0.x: | |||||
| Ignore AppleDouble Resource Fork Files. (Maybe we should ignore all | Ignore AppleDouble Resource Fork Files. (Maybe we should ignore all | ||||
| dot files.) | dot files.) | ||||
| Readded SOAPpy/fpconst requirement as it is necessary for twisted. | Readded SOAPpy/fpconst requirement as it is necessary for twisted. | ||||
| Made it a bit closer to a real twisted proejct, in the process, | |||||
| Made it a bit closer to a real twisted project, in the process, | |||||
| pymediaserv looks more like a normal program. It allows you to | pymediaserv looks more like a normal program. It allows you to | ||||
| override the media path and title of the server. | override the media path and title of the server. | ||||
| Minor change to checkUpdate API, we didn't use the return value, so | Minor change to checkUpdate API, we didn't use the return value, so | ||||
| @@ -91,6 +92,11 @@ v0.x: | |||||
| This means that you can support streaming radio stations that | This means that you can support streaming radio stations that | ||||
| provides a .pls file such as KCSM 91.1. | provides a .pls file such as KCSM 91.1. | ||||
| Fix ShoutCast error handling to be correct. | Fix ShoutCast error handling to be correct. | ||||
| Add support for an XML file containing an object so you can create | |||||
| an item that points to an mp3 streaming url that isn't a .pls. | |||||
| Add support for playing parts of TS streams. This is useful for | |||||
| splitting apart a TS stream w/ multiple clips (like HDV) w/o | |||||
| creating the files. | |||||
| v0.5: | v0.5: | ||||
| Support multiple SSDP servers on the same box. | Support multiple SSDP servers on the same box. | ||||
| @@ -3,7 +3,7 @@ | |||||
| # Licensed under the MIT license | # Licensed under the MIT license | ||||
| # http://opensource.org/licenses/mit-license.php | # http://opensource.org/licenses/mit-license.php | ||||
| # Copyright 2005, Tim Potter <tpot@samba.org> | # Copyright 2005, Tim Potter <tpot@samba.org> | ||||
| # Copyright 2006 John-Mark Gurney <jmg@funkthat.com> | |||||
| # Copyright 2006-2009 John-Mark Gurney <jmg@funkthat.com> | |||||
| __version__ = '$Change$' | __version__ = '$Change$' | ||||
| # $Id$ | # $Id$ | ||||
| @@ -29,6 +29,7 @@ def tryloadmodule(mod): | |||||
| # mpegtsmod can be really expensive. | # mpegtsmod can be really expensive. | ||||
| modules = [ | modules = [ | ||||
| 'shoutcast', | 'shoutcast', | ||||
| 'Clip', | |||||
| 'pyvr', | 'pyvr', | ||||
| 'item', | 'item', | ||||
| 'dvd', | 'dvd', | ||||