Subliminal update

This commit is contained in:
Ruud
2012-04-08 17:35:39 +02:00
parent 5321037f08
commit 148e1940ac
85 changed files with 4375 additions and 3420 deletions
+64 -66
View File
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# enzyme - Video metadata parser
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
# Copyright (C) 2003-2007 Thomas Schueppel <stain@acm.org>
# Copyright (C) 2003-2007 Dirk Meyer <dischi@freevo.org>
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
# Copyright 2003-2007 Thomas Schueppel <stain@acm.org>
# Copyright 2003-2007 Dirk Meyer <dischi@freevo.org>
#
# This file is part of enzyme.
#
@@ -17,16 +17,14 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# along with enzyme. If not, see <http://www.gnu.org/licenses/>.
__all__ = ['Parser']
import zlib
import logging
import StringIO
import struct
from exceptions import *
from exceptions import ParseError
import core
# get logging object
@@ -169,7 +167,7 @@ class MPEG4(core.AVContainer):
self.type = 'Quicktime Video'
h = file.read(8)
try:
(size, type) = struct.unpack('>I4s',h)
(size, type) = struct.unpack('>I4s', h)
except struct.error:
# EOF.
raise ParseError()
@@ -183,18 +181,18 @@ class MPEG4(core.AVContainer):
self.mime = 'video/mp4'
self.type = 'MPEG-4 Video'
size -= 4
file.seek(size-8, 1)
file.seek(size - 8, 1)
h = file.read(8)
(size, type) = struct.unpack('>I4s',h)
(size, type) = struct.unpack('>I4s', h)
while type in ['mdat', 'skip']:
# movie data at the beginning, skip
file.seek(size-8, 1)
file.seek(size - 8, 1)
h = file.read(8)
(size, type) = struct.unpack('>I4s',h)
(size, type) = struct.unpack('>I4s', h)
if not type in ['moov', 'wide', 'free']:
log.debug('invalid header: %r' % type)
log.debug(u'invalid header: %r' % type)
raise ParseError()
# Extended size
@@ -216,37 +214,37 @@ class MPEG4(core.AVContainer):
if len(s) < 8:
return 0
atomsize,atomtype = struct.unpack('>I4s', s)
atomsize, atomtype = struct.unpack('>I4s', s)
if not str(atomtype).decode('latin1').isalnum():
# stop at nonsense data
return 0
log.debug('%s [%X]' % (atomtype,atomsize))
log.debug(u'%r [%X]' % (atomtype, atomsize))
if atomtype == 'udta':
# Userdata (Metadata)
pos = 0
tabl = {}
i18ntabl = {}
atomdata = file.read(atomsize-8)
while pos < atomsize-12:
(datasize, datatype) = struct.unpack('>I4s', atomdata[pos:pos+8])
atomdata = file.read(atomsize - 8)
while pos < atomsize - 12:
(datasize, datatype) = struct.unpack('>I4s', atomdata[pos:pos + 8])
if ord(datatype[0]) == 169:
# i18n Metadata...
mypos = 8+pos
while mypos + 4 < datasize+pos:
mypos = 8 + pos
while mypos + 4 < datasize + pos:
# first 4 Bytes are i18n header
(tlen, lang) = struct.unpack('>HH', atomdata[mypos:mypos+4])
(tlen, lang) = struct.unpack('>HH', atomdata[mypos:mypos + 4])
i18ntabl[lang] = i18ntabl.get(lang, {})
l = atomdata[mypos+4:mypos+tlen+4]
l = atomdata[mypos + 4:mypos + tlen + 4]
i18ntabl[lang][datatype[1:]] = l
mypos += tlen+4
mypos += tlen + 4
elif datatype == 'WLOC':
# Drop Window Location
pass
else:
if ord(atomdata[pos+8:pos+datasize][0]) > 1:
tabl[datatype] = atomdata[pos+8:pos+datasize]
if ord(atomdata[pos + 8:pos + datasize][0]) > 1:
tabl[datatype] = atomdata[pos + 8:pos + datasize]
pos += datasize
if len(i18ntabl.keys()) > 0:
for k in i18ntabl.keys():
@@ -254,19 +252,19 @@ class MPEG4(core.AVContainer):
self._appendtable('QTUDTA', i18ntabl[k])
self._appendtable('QTUDTA', tabl)
else:
log.debug('NO i18')
log.debug(u'NO i18')
self._appendtable('QTUDTA', tabl)
elif atomtype == 'trak':
atomdata = file.read(atomsize-8)
atomdata = file.read(atomsize - 8)
pos = 0
trackinfo = {}
tracktype = None
while pos < atomsize-8:
(datasize, datatype) = struct.unpack('>I4s', atomdata[pos:pos+8])
while pos < atomsize - 8:
(datasize, datatype) = struct.unpack('>I4s', atomdata[pos:pos + 8])
if datatype == 'tkhd':
tkhd = struct.unpack('>6I8x4H36xII', atomdata[pos+8:pos+datasize])
tkhd = struct.unpack('>6I8x4H36xII', atomdata[pos + 8:pos + datasize])
trackinfo['width'] = tkhd[10] >> 16
trackinfo['height'] = tkhd[11] >> 16
trackinfo['id'] = tkhd[3]
@@ -277,23 +275,23 @@ class MPEG4(core.AVContainer):
# XXX Apple time. FIXME to work on Apple, too
self.timestamp = int(tkhd[1]) - 2082844800
except Exception, e:
log.exception('There was trouble extracting timestamp')
log.exception(u'There was trouble extracting timestamp')
elif datatype == 'mdia':
pos += 8
datasize -= 8
log.debug('--> mdia information')
log.debug(u'--> mdia information')
while datasize:
mdia = struct.unpack('>I4s', atomdata[pos:pos+8])
mdia = struct.unpack('>I4s', atomdata[pos:pos + 8])
if mdia[1] == 'mdhd':
# Parse based on version of mdhd header. See
# http://wiki.multimedia.cx/index.php?title=QuickTime_container#mdhd
ver = ord(atomdata[pos + 8])
if ver == 0:
mdhd = struct.unpack('>IIIIIhh', atomdata[pos+8:pos+8+24])
mdhd = struct.unpack('>IIIIIhh', atomdata[pos + 8:pos + 8 + 24])
elif ver == 1:
mdhd = struct.unpack('>IQQIQhh', atomdata[pos+8:pos+8+36])
mdhd = struct.unpack('>IQQIQhh', atomdata[pos + 8:pos + 8 + 36])
else:
mdhd = None
@@ -313,34 +311,34 @@ class MPEG4(core.AVContainer):
pos -= (mdia[0] - 8)
datasize += (mdia[0] - 8)
elif mdia[1] == 'hdlr':
hdlr = struct.unpack('>I4s4s', atomdata[pos+8:pos+8+12])
hdlr = struct.unpack('>I4s4s', atomdata[pos + 8:pos + 8 + 12])
if hdlr[1] == 'mhlr':
if hdlr[2] == 'vide':
tracktype = 'video'
if hdlr[2] == 'soun':
tracktype = 'audio'
elif mdia[1] == 'stsd':
stsd = struct.unpack('>2I', atomdata[pos+8:pos+8+8])
stsd = struct.unpack('>2I', atomdata[pos + 8:pos + 8 + 8])
if stsd[1] > 0:
codec = atomdata[pos+16:pos+16+8]
codec = atomdata[pos + 16:pos + 16 + 8]
codec = struct.unpack('>I4s', codec)
trackinfo['codec'] = codec[1]
if codec[1] == 'jpeg':
tracktype = 'image'
elif mdia[1] == 'dinf':
dref = struct.unpack('>I4s', atomdata[pos+8:pos+8+8])
log.debug(' --> %s, %s (useless)' % mdia)
dref = struct.unpack('>I4s', atomdata[pos + 8:pos + 8 + 8])
log.debug(u' --> %r, %r (useless)' % mdia)
if dref[1] == 'dref':
num = struct.unpack('>I', atomdata[pos+20:pos+20+4])[0]
rpos = pos+20+4
num = struct.unpack('>I', atomdata[pos + 20:pos + 20 + 4])[0]
rpos = pos + 20 + 4
for ref in range(num):
# FIXME: do somthing if this references
ref = struct.unpack('>I3s', atomdata[rpos:rpos+7])
data = atomdata[rpos+7:rpos+ref[0]]
ref = struct.unpack('>I3s', atomdata[rpos:rpos + 7])
data = atomdata[rpos + 7:rpos + ref[0]]
rpos += ref[0]
else:
if mdia[1].startswith('st'):
log.debug(' --> %s, %s (sample)' % mdia)
log.debug(u' --> %r, %r (sample)' % mdia)
elif mdia[1] == 'vmhd' and not tracktype:
# indicates that this track is video
tracktype = 'video'
@@ -348,19 +346,19 @@ class MPEG4(core.AVContainer):
# indicates that this track is audio
tracktype = 'audio'
else:
log.debug(' --> %s, %s (unknown)' % mdia)
log.debug(u' --> %r, %r (unknown)' % mdia)
pos += mdia[0]
datasize -= mdia[0]
elif datatype == 'udta':
log.debug(struct.unpack('>I4s', atomdata[:8]))
log.debug(u'udta: %r' % struct.unpack('>I4s', atomdata[:8]))
else:
if datatype == 'edts':
log.debug('--> %s [%d] (edit list)' % \
log.debug(u'--> %r [%d] (edit list)' % \
(datatype, datasize))
else:
log.debug('--> %s [%d] (unknown)' % \
log.debug(u'--> %r [%d] (unknown)' % \
(datatype, datasize))
pos += datasize
@@ -380,7 +378,7 @@ class MPEG4(core.AVContainer):
mvhd = struct.unpack('>6I2h', file.read(28))
self.length = max(self.length, mvhd[4] / mvhd[3])
self.volume = mvhd[6]
file.seek(atomsize-8-28,1)
file.seek(atomsize - 8 - 28, 1)
elif atomtype == 'cmov':
@@ -389,21 +387,21 @@ class MPEG4(core.AVContainer):
if not atomtype == 'dcom':
return atomsize
method = struct.unpack('>4s', file.read(datasize-8))[0]
method = struct.unpack('>4s', file.read(datasize - 8))[0]
datasize, atomtype = struct.unpack('>I4s', file.read(8))
if not atomtype == 'cmvd':
return atomsize
if method == 'zlib':
data = file.read(datasize-8)
data = file.read(datasize - 8)
try:
decompressed = zlib.decompress(data)
except Exception, e:
try:
decompressed = zlib.decompress(data[4:])
except Exception, e:
log.exception('There was a proble decompressiong atom')
log.exception(u'There was a proble decompressiong atom')
return atomsize
decompressedIO = StringIO.StringIO(decompressed)
@@ -411,9 +409,9 @@ class MPEG4(core.AVContainer):
pass
else:
log.info('unknown compression %s' % method)
log.info(u'unknown compression %r' % method)
# unknown compression method
file.seek(datasize-8,1)
file.seek(datasize - 8, 1)
elif atomtype == 'moov':
# decompressed movie info
@@ -423,10 +421,10 @@ class MPEG4(core.AVContainer):
elif atomtype == 'mdat':
pos = file.tell() + atomsize - 8
# maybe there is data inside the mdat
log.info('parsing mdat')
log.info(u'parsing mdat')
while self._readatom(file):
pass
log.info('end of mdat')
log.info(u'end of mdat')
file.seek(pos, 0)
@@ -437,24 +435,24 @@ class MPEG4(core.AVContainer):
elif atomtype == 'rmda':
# reference
atomdata = file.read(atomsize-8)
atomdata = file.read(atomsize - 8)
pos = 0
url = ''
quality = 0
datarate = 0
while pos < atomsize-8:
(datasize, datatype) = struct.unpack('>I4s', atomdata[pos:pos+8])
while pos < atomsize - 8:
(datasize, datatype) = struct.unpack('>I4s', atomdata[pos:pos + 8])
if datatype == 'rdrf':
rflags, rtype, rlen = struct.unpack('>I4sI', atomdata[pos+8:pos+20])
rflags, rtype, rlen = struct.unpack('>I4sI', atomdata[pos + 8:pos + 20])
if rtype == 'url ':
url = atomdata[pos+20:pos+20+rlen]
url = atomdata[pos + 20:pos + 20 + rlen]
if url.find('\0') > 0:
url = url[:url.find('\0')]
elif datatype == 'rmqu':
quality = struct.unpack('>I', atomdata[pos+8:pos+12])[0]
quality = struct.unpack('>I', atomdata[pos + 8:pos + 12])[0]
elif datatype == 'rmdr':
datarate = struct.unpack('>I', atomdata[pos+12:pos+16])[0]
datarate = struct.unpack('>I', atomdata[pos + 12:pos + 16])[0]
pos += datasize
if url:
@@ -462,11 +460,11 @@ class MPEG4(core.AVContainer):
else:
if not atomtype in ['wide', 'free']:
log.info('unhandled base atom %s' % atomtype)
log.info(u'unhandled base atom %r' % atomtype)
# Skip unknown atoms
try:
file.seek(atomsize-8,1)
file.seek(atomsize - 8, 1)
except IOError:
return 0