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', | ||||