Subliminal update
This commit is contained in:
+64
-66
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user