Subliminal update
This commit is contained in:
1 parent
5321037f08
commit
148e1940ac
85 files changed
+4375
-3420
No files matched your search
+15
-8
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -17,14 +17,13 @@
|
||||
# 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/>.
|
||||
import mimetypes
|
||||
import os
|
||||
import sys
|
||||
from exceptions import *
|
||||
|
||||
|
||||
PARSERS = [('asf', ['video/asf'], ['asf', 'wmv', 'wma']),
|
||||
('flv', ['video/flv'], ['flv']),
|
||||
('mkv', ['video/x-matroska', 'application/mkv'], ['mkv', 'mka', 'webm']),
|
||||
@@ -32,10 +31,18 @@ PARSERS = [('asf', ['video/asf'], ['asf', 'wmv', 'wma']),
|
||||
('mpeg', ['video/mpeg'], ['mpeg', 'mpg', 'mp4', 'ts']),
|
||||
('ogm', ['application/ogg'], ['ogm', 'ogg', 'ogv']),
|
||||
('real', ['video/real'], ['rm', 'ra', 'ram']),
|
||||
('riff', ['video/avi'], ['wav', 'avi'])]
|
||||
('riff', ['video/avi'], ['wav', 'avi'])
|
||||
]
|
||||
|
||||
|
||||
def parse(path):
|
||||
"""Parse metadata of the given video
|
||||
|
||||
:param string path: path to the video file to parse
|
||||
:return: a parser corresponding to the video's mimetype or extension
|
||||
:rtype: :class:`~enzyme.core.AVContainer`
|
||||
|
||||
"""
|
||||
if not os.path.isfile(path):
|
||||
raise ValueError('Invalid path')
|
||||
extension = os.path.splitext(path)[1][1:]
|
||||
@@ -47,7 +54,7 @@ def parse(path):
|
||||
parser_mime = parser_name
|
||||
if extension in parser_extensions:
|
||||
parser_ext = parser_name
|
||||
parser = parser_mime or parser_ext
|
||||
parser = parser_mime or parser_ext
|
||||
if not parser:
|
||||
raise NoParserError()
|
||||
mod = __import__(parser, globals=globals(), locals=locals(), fromlist=[], level=-1)
|
||||
|
||||
+62
-64
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -17,30 +17,29 @@
|
||||
# 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/>.
|
||||
from exceptions import ParseError
|
||||
import core
|
||||
import logging
|
||||
import string
|
||||
import struct
|
||||
|
||||
|
||||
__all__ = ['Parser']
|
||||
|
||||
import struct
|
||||
import string
|
||||
import logging
|
||||
from exceptions import *
|
||||
import core
|
||||
|
||||
# get logging object
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def _guid(input):
|
||||
# Remove any '-'
|
||||
s = string.join(string.split(input,'-'), '')
|
||||
s = string.join(string.split(input, '-'), '')
|
||||
r = ''
|
||||
if len(s) != 32:
|
||||
return ''
|
||||
x = ''
|
||||
for i in range(0,16):
|
||||
r+=chr(int(s[2*i:2*i+2],16))
|
||||
guid = struct.unpack('>IHHBB6s',r)
|
||||
for i in range(0, 16):
|
||||
r += chr(int(s[2 * i:2 * i + 2], 16))
|
||||
guid = struct.unpack('>IHHBB6s', r)
|
||||
return guid
|
||||
|
||||
GUIDS = {
|
||||
@@ -93,8 +92,7 @@ GUIDS = {
|
||||
'ASF_Web_Stream_Format' : _guid('DA1E6B13-8359-4050-B398-388E965BF00C'),
|
||||
|
||||
'ASF_No_Error_Correction' : _guid('20FB5700-5B55-11CF-A8FD-00805F5C442B'),
|
||||
'ASF_Audio_Spread' : _guid('BFC3CD50-618F-11CF-8BB2-00AA00B4E220'),
|
||||
}
|
||||
'ASF_Audio_Spread' : _guid('BFC3CD50-618F-11CF-8BB2-00AA00B4E220')}
|
||||
|
||||
|
||||
class Asf(core.AVContainer):
|
||||
@@ -114,7 +112,7 @@ class Asf(core.AVContainer):
|
||||
raise ParseError()
|
||||
|
||||
(guidstr, objsize, objnum, reserved1, \
|
||||
reserved2) = struct.unpack('<16sQIBB',h)
|
||||
reserved2) = struct.unpack('<16sQIBB', h)
|
||||
guid = self._parseguid(guidstr)
|
||||
|
||||
if (guid != GUIDS['ASF_Header_Object']):
|
||||
@@ -122,9 +120,9 @@ class Asf(core.AVContainer):
|
||||
if reserved1 != 0x01 or reserved2 != 0x02:
|
||||
raise ParseError()
|
||||
|
||||
log.debug("asf header size: %d / %d objects" % (objsize,objnum))
|
||||
header = file.read(objsize-30)
|
||||
for i in range(0,objnum):
|
||||
log.debug(u'Header size: %d / %d objects' % (objsize, objnum))
|
||||
header = file.read(objsize - 30)
|
||||
for _ in range(0, objnum):
|
||||
h = self._getnextheader(header)
|
||||
header = header[h[1]:]
|
||||
|
||||
@@ -148,19 +146,19 @@ class Asf(core.AVContainer):
|
||||
stream._appendtable('ASFMETADATA', metadata)
|
||||
|
||||
|
||||
def _parseguid(self,string):
|
||||
def _parseguid(self, string):
|
||||
return struct.unpack('<IHHBB6s', string[:16])
|
||||
|
||||
|
||||
def _parsekv(self,s):
|
||||
def _parsekv(self, s):
|
||||
pos = 0
|
||||
(descriptorlen,) = struct.unpack('<H', s[pos:pos+2])
|
||||
(descriptorlen,) = struct.unpack('<H', s[pos:pos + 2])
|
||||
pos += 2
|
||||
descriptorname = s[pos:pos+descriptorlen]
|
||||
descriptorname = s[pos:pos + descriptorlen]
|
||||
pos += descriptorlen
|
||||
descriptortype, valuelen = struct.unpack('<HH', s[pos:pos+4])
|
||||
descriptortype, valuelen = struct.unpack('<HH', s[pos:pos + 4])
|
||||
pos += 4
|
||||
descriptorvalue = s[pos:pos+valuelen]
|
||||
descriptorvalue = s[pos:pos + valuelen]
|
||||
pos += valuelen
|
||||
value = None
|
||||
if descriptortype == 0x0000:
|
||||
@@ -182,17 +180,17 @@ class Asf(core.AVContainer):
|
||||
# WORD
|
||||
value = struct.unpack('<H', descriptorvalue)[0]
|
||||
else:
|
||||
log.debug("Unknown Descriptor Type %d" % descriptortype)
|
||||
return (pos,descriptorname,value)
|
||||
log.debug(u'Unknown Descriptor Type %d' % descriptortype)
|
||||
return (pos, descriptorname, value)
|
||||
|
||||
|
||||
def _parsekv2(self,s):
|
||||
def _parsekv2(self, s):
|
||||
pos = 0
|
||||
strno, descriptorlen, descriptortype, valuelen = struct.unpack('<2xHHHI', s[pos:pos+12])
|
||||
strno, descriptorlen, descriptortype, valuelen = struct.unpack('<2xHHHI', s[pos:pos + 12])
|
||||
pos += 12
|
||||
descriptorname = s[pos:pos+descriptorlen]
|
||||
descriptorname = s[pos:pos + descriptorlen]
|
||||
pos += descriptorlen
|
||||
descriptorvalue = s[pos:pos+valuelen]
|
||||
descriptorvalue = s[pos:pos + valuelen]
|
||||
pos += valuelen
|
||||
value = None
|
||||
|
||||
@@ -216,25 +214,25 @@ class Asf(core.AVContainer):
|
||||
# WORD
|
||||
value = struct.unpack('<H', descriptorvalue)[0]
|
||||
else:
|
||||
log.debug("Unknown Descriptor Type %d" % descriptortype)
|
||||
return (pos,descriptorname,value,strno)
|
||||
log.debug(u'Unknown Descriptor Type %d' % descriptortype)
|
||||
return (pos, descriptorname, value, strno)
|
||||
|
||||
|
||||
def _getnextheader(self,s):
|
||||
r = struct.unpack('<16sQ',s[:24])
|
||||
(guidstr,objsize) = r
|
||||
def _getnextheader(self, s):
|
||||
r = struct.unpack('<16sQ', s[:24])
|
||||
(guidstr, objsize) = r
|
||||
guid = self._parseguid(guidstr)
|
||||
if guid == GUIDS['ASF_File_Properties_Object']:
|
||||
log.debug("File Properties Object")
|
||||
val = struct.unpack('<16s6Q4I',s[24:24+80])
|
||||
log.debug(u'File Properties Object')
|
||||
val = struct.unpack('<16s6Q4I', s[24:24 + 80])
|
||||
(fileid, size, date, packetcount, duration, \
|
||||
senddur, preroll, flags, minpack, maxpack, maxbr) = \
|
||||
val
|
||||
# FIXME: parse date to timestamp
|
||||
self.length = duration/10000000.0
|
||||
self.length = duration / 10000000.0
|
||||
|
||||
elif guid == GUIDS['ASF_Stream_Properties_Object']:
|
||||
log.debug("Stream Properties Object [%d]" % objsize)
|
||||
log.debug(u'Stream Properties Object [%d]' % objsize)
|
||||
streamtype = self._parseguid(s[24:40])
|
||||
errortype = self._parseguid(s[40:56])
|
||||
offset, typelen, errorlen, flags = struct.unpack('<QIIH', s[56:74])
|
||||
@@ -244,15 +242,15 @@ class Asf(core.AVContainer):
|
||||
self._set('encrypted', True)
|
||||
if streamtype == GUIDS['ASF_Video_Media']:
|
||||
vi = core.VideoStream()
|
||||
vi.width, vi.height, depth, codec, = struct.unpack('<4xII2xH4s', s[89:89+20])
|
||||
vi.width, vi.height, depth, codec, = struct.unpack('<4xII2xH4s', s[89:89 + 20])
|
||||
vi.codec = codec
|
||||
vi.id = strno
|
||||
self.video.append(vi)
|
||||
elif streamtype == GUIDS['ASF_Audio_Media']:
|
||||
ai = core.AudioStream()
|
||||
twocc, ai.channels, ai.samplerate, bitrate, block, \
|
||||
ai.samplebits, = struct.unpack('<HHIIHH', s[78:78+16])
|
||||
ai.bitrate = 8*bitrate
|
||||
ai.samplebits, = struct.unpack('<HHIIHH', s[78:78 + 16])
|
||||
ai.bitrate = 8 * bitrate
|
||||
ai.codec = twocc
|
||||
ai.id = strno
|
||||
self.audio.append(ai)
|
||||
@@ -260,8 +258,8 @@ class Asf(core.AVContainer):
|
||||
self._apply_extinfo(strno)
|
||||
|
||||
elif guid == GUIDS['ASF_Extended_Stream_Properties_Object']:
|
||||
streamid, langid, frametime = struct.unpack('<HHQ',s[72:84])
|
||||
(bitrate,) = struct.unpack('<I', s[40:40+4])
|
||||
streamid, langid, frametime = struct.unpack('<HHQ', s[72:84])
|
||||
(bitrate,) = struct.unpack('<I', s[40:40 + 4])
|
||||
if streamid not in self._extinfo:
|
||||
self._extinfo[streamid] = [None, None, None, {}]
|
||||
if frametime == 0:
|
||||
@@ -271,31 +269,31 @@ class Asf(core.AVContainer):
|
||||
self._apply_extinfo(streamid)
|
||||
|
||||
elif guid == GUIDS['ASF_Header_Extension_Object']:
|
||||
log.debug("ASF_Header_Extension_Object %d" % objsize)
|
||||
size = struct.unpack('<I',s[42:46])[0]
|
||||
data = s[46:46+size]
|
||||
log.debug(u'ASF_Header_Extension_Object %d' % objsize)
|
||||
size = struct.unpack('<I', s[42:46])[0]
|
||||
data = s[46:46 + size]
|
||||
while len(data):
|
||||
log.debug("Sub:")
|
||||
log.debug(u'Sub:')
|
||||
h = self._getnextheader(data)
|
||||
data = data[h[1]:]
|
||||
|
||||
elif guid == GUIDS['ASF_Codec_List_Object']:
|
||||
log.debug("List Object")
|
||||
log.debug(u'List Object')
|
||||
pass
|
||||
|
||||
elif guid == GUIDS['ASF_Error_Correction_Object']:
|
||||
log.debug("Error Correction")
|
||||
log.debug(u'Error Correction')
|
||||
pass
|
||||
|
||||
elif guid == GUIDS['ASF_Content_Description_Object']:
|
||||
log.debug("Content Description Object")
|
||||
val = struct.unpack('<5H', s[24:24+10])
|
||||
log.debug(u'Content Description Object')
|
||||
val = struct.unpack('<5H', s[24:24 + 10])
|
||||
pos = 34
|
||||
strings = []
|
||||
for i in val:
|
||||
ss = s[pos:pos+i].replace('\0', '').lstrip().rstrip()
|
||||
ss = s[pos:pos + i].replace('\0', '').lstrip().rstrip()
|
||||
strings.append(ss)
|
||||
pos+=i
|
||||
pos += i
|
||||
|
||||
# Set empty strings to None
|
||||
strings = [x or None for x in strings]
|
||||
@@ -318,7 +316,7 @@ class Asf(core.AVContainer):
|
||||
streams = {}
|
||||
for i in range(0, count):
|
||||
# Read additional content descriptors
|
||||
size,key,value,strno = self._parsekv2(s[pos:])
|
||||
size, key, value, strno = self._parsekv2(s[pos:])
|
||||
if strno not in streams:
|
||||
streams[strno] = {}
|
||||
streams[strno][key] = value
|
||||
@@ -334,12 +332,12 @@ class Asf(core.AVContainer):
|
||||
count = struct.unpack('<H', s[24:26])[0]
|
||||
pos = 26
|
||||
for i in range(0, count):
|
||||
idlen = struct.unpack('<B', s[pos:pos+1])[0]
|
||||
idstring = s[pos+1:pos+1+idlen]
|
||||
idlen = struct.unpack('<B', s[pos:pos + 1])[0]
|
||||
idstring = s[pos + 1:pos + 1 + idlen]
|
||||
idstring = unicode(idstring, 'utf-16').replace('\0', '')
|
||||
log.debug("Language: %d/%d: %s" % (i+1, count, idstring))
|
||||
log.debug(u'Language: %d/%d: %r' % (i + 1, count, idstring))
|
||||
self._languages.append(idstring)
|
||||
pos += 1+idlen
|
||||
pos += 1 + idlen
|
||||
|
||||
elif guid == GUIDS['ASF_Stream_Bitrate_Properties_Object']:
|
||||
# This record contains stream bitrate with payload overhead. For
|
||||
@@ -356,11 +354,11 @@ class Asf(core.AVContainer):
|
||||
# Just print the type:
|
||||
for h in GUIDS.keys():
|
||||
if GUIDS[h] == guid:
|
||||
log.debug("Unparsed %s [%d]" % (h,objsize))
|
||||
log.debug(u'Unparsed %r [%d]' % (h, objsize))
|
||||
break
|
||||
else:
|
||||
u = "%.8X-%.4X-%.4X-%.2X%.2X-%s" % guid
|
||||
log.debug("unknown: len=%d [%d]" % (len(u), objsize))
|
||||
log.debug(u'unknown: len=%d [%d]' % (len(u), objsize))
|
||||
return r
|
||||
|
||||
|
||||
|
||||
+26
-33
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -17,21 +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/>.
|
||||
import re
|
||||
import logging
|
||||
import fourcc
|
||||
import language
|
||||
from exceptions import *
|
||||
from strutils import str_to_unicode, unicode_to_str
|
||||
|
||||
UNPRINTABLE_KEYS = ['thumbnail', 'url', 'codec_private']
|
||||
EXTENSION_DEVICE = 'device'
|
||||
EXTENSION_DIRECTORY = 'directory'
|
||||
EXTENSION_STREAM = 'stream'
|
||||
MEDIACORE = ['title', 'caption', 'comment', 'size', 'type', 'subtype', 'timestamp',
|
||||
'keywords', 'country', 'language', 'langcode', 'url', 'artist',
|
||||
'mime', 'datetime', 'tags', 'hash']
|
||||
@@ -52,8 +45,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Media(object):
|
||||
media = None
|
||||
|
||||
"""
|
||||
Media is the base class to all Media Metadata Containers. It defines
|
||||
the basic structures that handle metadata. Media and its derivates
|
||||
@@ -61,10 +52,11 @@ class Media(object):
|
||||
Specific derivates contain additional keys to the dublin core set that is
|
||||
defined in Media.
|
||||
"""
|
||||
media = None
|
||||
_keys = MEDIACORE
|
||||
table_mapping = {}
|
||||
|
||||
def __init__(self, hash = None):
|
||||
def __init__(self, hash=None):
|
||||
if hash is not None:
|
||||
# create Media based on dict
|
||||
for key, value in hash.items():
|
||||
@@ -139,20 +131,21 @@ class Media(object):
|
||||
result += '| ' + re.sub(r'\n(.)', r'\n| \1', unicode(item))
|
||||
|
||||
# print tables
|
||||
if log.level >= 10:
|
||||
for name, table in self.tables.items():
|
||||
result += '+-- Table %s\n' % str(name)
|
||||
for key, value in table.items():
|
||||
try:
|
||||
value = unicode(value)
|
||||
if len(value) > 50:
|
||||
value = u'<unprintable data, size=%d>' % len(value)
|
||||
except (UnicodeDecodeError, TypeError), e:
|
||||
try:
|
||||
value = u'<unprintable data, size=%d>' % len(value)
|
||||
except AttributeError:
|
||||
value = u'<unprintable data>'
|
||||
result += u'| | %s: %s\n' % (unicode(key), value)
|
||||
#FIXME: WTH?
|
||||
# if log.level >= 10:
|
||||
# for name, table in self.tables.items():
|
||||
# result += '+-- Table %s\n' % str(name)
|
||||
# for key, value in table.items():
|
||||
# try:
|
||||
# value = unicode(value)
|
||||
# if len(value) > 50:
|
||||
# value = u'<unprintable data, size=%d>' % len(value)
|
||||
# except (UnicodeDecodeError, TypeError):
|
||||
# try:
|
||||
# value = u'<unprintable data, size=%d>' % len(value)
|
||||
# except AttributeError:
|
||||
# value = u'<unprintable data>'
|
||||
# result += u'| | %s: %s\n' % (unicode(key), value)
|
||||
return result
|
||||
|
||||
def __str__(self):
|
||||
@@ -253,7 +246,7 @@ class Media(object):
|
||||
"""
|
||||
return hasattr(self, key)
|
||||
|
||||
def get(self, attr, default = None):
|
||||
def get(self, attr, default=None):
|
||||
"""
|
||||
Returns the given attribute. If the attribute is not set by
|
||||
the parser return 'default'.
|
||||
@@ -315,7 +308,7 @@ class Tag(object):
|
||||
Tag values are strings (for binary data), unicode objects, or datetime
|
||||
objects for tags that represent dates or times.
|
||||
"""
|
||||
def __init__(self, value = None, langcode = 'und', binary = False):
|
||||
def __init__(self, value=None, langcode='und', binary=False):
|
||||
super(Tag, self).__init__()
|
||||
self.value = value
|
||||
self.langcode = langcode
|
||||
@@ -363,7 +356,7 @@ class Tags(dict, Tag):
|
||||
The attribute RATING has a value (PG), but it also has a child tag
|
||||
COUNTRY that specifies the country code the rating belongs to.
|
||||
"""
|
||||
def __init__(self, value = None, langcode = 'und', binary = False):
|
||||
def __init__(self, value=None, langcode='und', binary=False):
|
||||
super(Tags, self).__init__()
|
||||
self.value = value
|
||||
self.langcode = langcode
|
||||
@@ -410,7 +403,7 @@ class Chapter(Media):
|
||||
"""
|
||||
_keys = ['enabled', 'name', 'pos', 'id']
|
||||
|
||||
def __init__(self, name = None, pos = 0):
|
||||
def __init__(self, name=None, pos=0):
|
||||
Media.__init__(self)
|
||||
self.name = name
|
||||
self.pos = pos
|
||||
@@ -424,7 +417,7 @@ class Subtitle(Media):
|
||||
_keys = ['enabled', 'default', 'langcode', 'language', 'trackno', 'title',
|
||||
'id', 'codec']
|
||||
|
||||
def __init__(self, language = None):
|
||||
def __init__(self, language=None):
|
||||
Media.__init__(self)
|
||||
self.language = language
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -15,10 +15,7 @@
|
||||
# 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/>.
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
|
||||
+17
-18
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -16,16 +16,15 @@
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
__all__ = ['Parser']
|
||||
|
||||
from exceptions import *
|
||||
# along with enzyme. If not, see <http://www.gnu.org/licenses/>.
|
||||
from exceptions import ParseError
|
||||
import core
|
||||
import logging
|
||||
import struct
|
||||
|
||||
__all__ = ['Parser']
|
||||
|
||||
|
||||
# get logging object
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -44,7 +43,7 @@ FLV_AUDIO_CODECID = (0x0001, 0x0002, 0x0055, 0x0001)
|
||||
|
||||
# video flags
|
||||
FLV_VIDEO_CODECID_MASK = 0x0f
|
||||
FLV_VIDEO_CODECID = ( 'FLV1', 'MSS1', 'VP60') # wild guess
|
||||
FLV_VIDEO_CODECID = ('FLV1', 'MSS1', 'VP60') # wild guess
|
||||
|
||||
FLV_DATA_TYPE_NUMBER = 0x00
|
||||
FLV_DATA_TYPE_BOOL = 0x01
|
||||
@@ -70,7 +69,7 @@ class FlashVideo(core.AVContainer):
|
||||
"""
|
||||
table_mapping = { 'FLVINFO' : FLVINFO }
|
||||
|
||||
def __init__(self,file):
|
||||
def __init__(self, file):
|
||||
core.AVContainer.__init__(self)
|
||||
self.mime = 'video/flv'
|
||||
self.type = 'Flash Video'
|
||||
@@ -78,7 +77,7 @@ class FlashVideo(core.AVContainer):
|
||||
if len(data) < 13 or struct.unpack('>3sBBII', data)[0] != 'FLV':
|
||||
raise ParseError()
|
||||
|
||||
for i in range(10):
|
||||
for _ in range(10):
|
||||
if self.audio and self.video:
|
||||
break
|
||||
data = file.read(11)
|
||||
@@ -116,13 +115,13 @@ class FlashVideo(core.AVContainer):
|
||||
file.seek(size - 1, 1)
|
||||
|
||||
elif chunk[0] == FLV_TAG_TYPE_META:
|
||||
log.info('metadata %s', str(chunk))
|
||||
log.info(u'metadata %r', str(chunk))
|
||||
metadata = file.read(size)
|
||||
try:
|
||||
while metadata:
|
||||
length, value = self._parse_value(metadata)
|
||||
if isinstance(value, dict):
|
||||
log.info('metadata: %s', value)
|
||||
log.info(u'metadata: %r', value)
|
||||
if value.get('creator'):
|
||||
self.copyright = value.get('creator')
|
||||
if value.get('width'):
|
||||
@@ -139,7 +138,7 @@ class FlashVideo(core.AVContainer):
|
||||
except (IndexError, struct.error, TypeError):
|
||||
pass
|
||||
else:
|
||||
log.info('unkown %s', str(chunk))
|
||||
log.info(u'unkown %r', str(chunk))
|
||||
file.seek(size, 1)
|
||||
|
||||
file.seek(4, 1)
|
||||
@@ -157,16 +156,16 @@ class FlashVideo(core.AVContainer):
|
||||
|
||||
if ord(data[0]) == FLV_DATA_TYPE_STRING:
|
||||
length = (ord(data[1]) << 8) + ord(data[2])
|
||||
return length + 3, data[3:length+3]
|
||||
return length + 3, data[3:length + 3]
|
||||
|
||||
if ord(data[0]) == FLV_DATA_TYPE_ECMARRAY:
|
||||
init_length = len(data)
|
||||
num = struct.unpack('>I', data[1:5])[0]
|
||||
data = data[5:]
|
||||
result = {}
|
||||
for i in range(num):
|
||||
for _ in range(num):
|
||||
length = (ord(data[0]) << 8) + ord(data[1])
|
||||
key = data[2:length+2]
|
||||
key = data[2:length + 2]
|
||||
data = data[length + 2:]
|
||||
length, value = self._parse_value(data)
|
||||
if not length:
|
||||
@@ -175,7 +174,7 @@ class FlashVideo(core.AVContainer):
|
||||
data = data[length:]
|
||||
return init_length - len(data), result
|
||||
|
||||
log.info('unknown code: %x. Stop metadata parser', ord(data[0]))
|
||||
log.info(u'unknown code: %x. Stop metadata parser', ord(data[0]))
|
||||
return 0, None
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -16,10 +16,7 @@
|
||||
# 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/>.
|
||||
import string
|
||||
import re
|
||||
import struct
|
||||
|
||||
+3
-10
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -15,12 +15,5 @@
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
__title__ = 'enzyme'
|
||||
__description__ = 'Video metadata parser'
|
||||
__version__ = '0.1'
|
||||
__author__ = 'Antoine Bertin'
|
||||
__email__ = 'diaoulael@gmail.com'
|
||||
__license__ = 'GPLv3'
|
||||
# along with enzyme. If not, see <http://www.gnu.org/licenses/>.
|
||||
__version__ = '0.2'
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -16,10 +16,7 @@
|
||||
# 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/>.
|
||||
import re
|
||||
|
||||
__all__ = ['resolve']
|
||||
@@ -44,7 +41,7 @@ def resolve(code):
|
||||
if code in spec[:-1]:
|
||||
return code, spec[-1]
|
||||
|
||||
return code, u'Unknown (%s)' % code
|
||||
return code, u'Unknown (%r)' % code
|
||||
|
||||
|
||||
# Parsed from http://www.loc.gov/standards/iso639-2/ISO-639-2_utf-8.txt
|
||||
|
||||
+33
-34
@@ -1,9 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright (C) 2003-2006 Jason Tackaberry <tack@urandom.ca>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2003-2006 Jason Tackaberry <tack@urandom.ca>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -18,18 +18,17 @@
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
__all__ = ['Parser']
|
||||
|
||||
# along with enzyme. If not, see <http://www.gnu.org/licenses/>.
|
||||
from datetime import datetime
|
||||
from exceptions import *
|
||||
from exceptions import ParseError
|
||||
from struct import unpack
|
||||
import core
|
||||
import logging
|
||||
import re
|
||||
|
||||
__all__ = ['Parser']
|
||||
|
||||
|
||||
# get logging object
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -236,7 +235,7 @@ class EbmlEntity:
|
||||
self.compute_id(inbuf)
|
||||
|
||||
if self.id_len == 0:
|
||||
log.error("EBML entity not found, bad file format")
|
||||
log.error(u'EBML entity not found, bad file format')
|
||||
raise ParseError()
|
||||
|
||||
self.entity_len, self.len_size = self.compute_len(inbuf[self.id_len:])
|
||||
@@ -247,7 +246,7 @@ class EbmlEntity:
|
||||
# if the data size is 8 or less, it could be a numeric value
|
||||
self.value = 0
|
||||
if self.entity_len <= 8:
|
||||
for pos, shift in zip(range(self.entity_len), range((self.entity_len-1)*8, -1, -8)):
|
||||
for pos, shift in zip(range(self.entity_len), range((self.entity_len - 1) * 8, -1, -8)):
|
||||
self.value |= ord(self.entity_data[pos]) << shift
|
||||
|
||||
|
||||
@@ -271,19 +270,19 @@ class EbmlEntity:
|
||||
if len(inbuf) < 2:
|
||||
return 0
|
||||
self.id_len = 2
|
||||
self.entity_id = ord(inbuf[0])<<8 | ord(inbuf[1])
|
||||
self.entity_id = ord(inbuf[0]) << 8 | ord(inbuf[1])
|
||||
elif first & 0x20:
|
||||
if len(inbuf) < 3:
|
||||
return 0
|
||||
self.id_len = 3
|
||||
self.entity_id = (ord(inbuf[0])<<16) | (ord(inbuf[1])<<8) | \
|
||||
self.entity_id = (ord(inbuf[0]) << 16) | (ord(inbuf[1]) << 8) | \
|
||||
(ord(inbuf[2]))
|
||||
elif first & 0x10:
|
||||
if len(inbuf) < 4:
|
||||
return 0
|
||||
self.id_len = 4
|
||||
self.entity_id = (ord(inbuf[0])<<24) | (ord(inbuf[1])<<16) | \
|
||||
(ord(inbuf[2])<<8) | (ord(inbuf[3]))
|
||||
self.entity_id = (ord(inbuf[0]) << 24) | (ord(inbuf[1]) << 16) | \
|
||||
(ord(inbuf[2]) << 8) | (ord(inbuf[3]))
|
||||
self.entity_str = inbuf[0:self.id_len]
|
||||
|
||||
|
||||
@@ -381,7 +380,7 @@ class Matroska(core.AVContainer):
|
||||
if header.get_id() != MATROSKA_HEADER_ID:
|
||||
raise ParseError()
|
||||
|
||||
log.debug("HEADER ID found %08X" % header.get_id() )
|
||||
log.debug(u'HEADER ID found %08X' % header.get_id())
|
||||
self.mime = 'video/x-matroska'
|
||||
self.type = 'Matroska'
|
||||
self.has_idx = False
|
||||
@@ -392,10 +391,10 @@ class Matroska(core.AVContainer):
|
||||
# Record file offset of segment data for seekheads
|
||||
self.segment.offset = header.get_total_len() + segment.get_header_len()
|
||||
if segment.get_id() != MATROSKA_SEGMENT_ID:
|
||||
log.debug("SEGMENT ID not found %08X" % segment.get_id())
|
||||
log.debug(u'SEGMENT ID not found %08X' % segment.get_id())
|
||||
return
|
||||
|
||||
log.debug("SEGMENT ID found %08X" % segment.get_id())
|
||||
log.debug(u'SEGMENT ID found %08X' % segment.get_id())
|
||||
try:
|
||||
for elem in self.process_one_level(segment):
|
||||
if elem.get_id() == MATROSKA_SEEKHEAD_ID:
|
||||
@@ -404,12 +403,12 @@ class Matroska(core.AVContainer):
|
||||
pass
|
||||
|
||||
if not self.has_idx:
|
||||
log.warning('File has no index')
|
||||
log.warning(u'File has no index')
|
||||
self._set('corrupt', True)
|
||||
|
||||
def process_elem(self, elem):
|
||||
elem_id = elem.get_id()
|
||||
log.debug('BEGIN: process element %s' % hex(elem_id))
|
||||
log.debug(u'BEGIN: process element %r' % hex(elem_id))
|
||||
if elem_id == MATROSKA_SEGMENT_INFO_ID:
|
||||
duration = 0
|
||||
scalecode = 1000000.0
|
||||
@@ -423,7 +422,7 @@ class Matroska(core.AVContainer):
|
||||
elif ielem_id == MATROSKA_TITLE_ID:
|
||||
self.title = ielem.get_utf8()
|
||||
elif ielem_id == MATROSKA_DATE_UTC_ID:
|
||||
timestamp = unpack('!q', ielem.get_data())[0] / 10.0**9
|
||||
timestamp = unpack('!q', ielem.get_data())[0] / 10.0 ** 9
|
||||
# Date is offset 2001-01-01 00:00:00 (timestamp 978307200.0)
|
||||
self.timestamp = int(timestamp + 978307200)
|
||||
|
||||
@@ -447,7 +446,7 @@ class Matroska(core.AVContainer):
|
||||
elif elem_id == MATROSKA_CUES_ID:
|
||||
self.has_idx = True
|
||||
|
||||
log.debug('END: process element %s' % hex(elem_id))
|
||||
log.debug(u'END: process element %r' % hex(elem_id))
|
||||
return True
|
||||
|
||||
|
||||
@@ -479,7 +478,7 @@ class Matroska(core.AVContainer):
|
||||
index = 0
|
||||
while index < tracks.get_len():
|
||||
trackelem = EbmlEntity(tracksbuf[index:])
|
||||
log.debug ("ELEMENT %X found" % trackelem.get_id())
|
||||
log.debug (u'ELEMENT %X found' % trackelem.get_id())
|
||||
self.process_track(trackelem)
|
||||
index += trackelem.get_total_len() + trackelem.get_crc_len()
|
||||
|
||||
@@ -503,20 +502,20 @@ class Matroska(core.AVContainer):
|
||||
elements = [x for x in self.process_one_level(track)]
|
||||
track_type = [x.get_value() for x in elements if x.get_id() == MATROSKA_TRACK_TYPE_ID]
|
||||
if not track_type:
|
||||
log.debug('Bad track: no type id found')
|
||||
log.debug(u'Bad track: no type id found')
|
||||
return
|
||||
|
||||
track_type = track_type[0]
|
||||
track = None
|
||||
|
||||
if track_type == MATROSKA_VIDEO_TRACK:
|
||||
log.debug("Video track found")
|
||||
log.debug(u'Video track found')
|
||||
track = self.process_video_track(elements)
|
||||
elif track_type == MATROSKA_AUDIO_TRACK:
|
||||
log.debug("Audio track found")
|
||||
log.debug(u'Audio track found')
|
||||
track = self.process_audio_track(elements)
|
||||
elif track_type == MATROSKA_SUBTITLES_TRACK:
|
||||
log.debug("Subtitle track found")
|
||||
log.debug(u'Subtitle track found')
|
||||
track = core.Subtitle()
|
||||
self.set_track_defaults(track)
|
||||
track.id = len(self.subtitles)
|
||||
@@ -529,7 +528,7 @@ class Matroska(core.AVContainer):
|
||||
elem_id = elem.get_id()
|
||||
if elem_id == MATROSKA_TRACK_LANGUAGE_ID:
|
||||
track.language = elem.get_str()
|
||||
log.debug("Track language found: %s" % track.language)
|
||||
log.debug(u'Track language found: %r' % track.language)
|
||||
elif elem_id == MATROSKA_NAME_ID:
|
||||
track.title = elem.get_utf8()
|
||||
elif elem_id == MATROSKA_TRACK_NUMBER_ID:
|
||||
@@ -671,7 +670,7 @@ class Matroska(core.AVContainer):
|
||||
elif elem_id == MATROSKA_CHAPTER_UID_ID:
|
||||
self.objects_by_uid[elem.get_value()] = chap
|
||||
|
||||
log.debug('Chapter "%s" found', chap.name)
|
||||
log.debug(u'Chapter %r found', chap.name)
|
||||
chap.id = len(self.chapters)
|
||||
self.chapters.append(chap)
|
||||
|
||||
@@ -704,10 +703,10 @@ class Matroska(core.AVContainer):
|
||||
|
||||
# Right now we only support attachments that could be cover images.
|
||||
# Make a guess to see if this attachment is a cover image.
|
||||
if mimetype.startswith("image/") and u"cover" in (name+desc).lower() and data:
|
||||
if mimetype.startswith("image/") and u"cover" in (name + desc).lower() and data:
|
||||
self.thumbnail = data
|
||||
|
||||
log.debug('Attachment "%s" found' % name)
|
||||
log.debug(u'Attachment %r found' % name)
|
||||
|
||||
|
||||
def process_tags(self, tags):
|
||||
@@ -744,7 +743,7 @@ class Matroska(core.AVContainer):
|
||||
self.objects_by_uid[target].tags.update(tags_dict)
|
||||
self.tags_to_attributes(self.objects_by_uid[target], tags_dict)
|
||||
except KeyError:
|
||||
log.warning('Tags assigned to unknown/unsupported target uid %d', target)
|
||||
log.warning(u'Tags assigned to unknown/unsupported target uid %d', target)
|
||||
else:
|
||||
self.tags.update(tags_dict)
|
||||
self.tags_to_attributes(self, tags_dict)
|
||||
@@ -816,7 +815,7 @@ class Matroska(core.AVContainer):
|
||||
try:
|
||||
value = [filter(item) for item in value] if isinstance(value, list) else filter(value)
|
||||
except Exception, e:
|
||||
log.warning('Failed to convert tag to core attribute: %s', e)
|
||||
log.warning(u'Failed to convert tag to core attribute: %r', e)
|
||||
# Special handling for tv series recordings. The 'title' tag
|
||||
# can be used for both the series and the episode name. The
|
||||
# same is true for trackno which may refer to the season
|
||||
|
||||
+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
|
||||
|
||||
|
||||
+89
-91
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright 2003-2006 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 os
|
||||
import struct
|
||||
import logging
|
||||
import stat
|
||||
from exceptions import *
|
||||
from exceptions import ParseError
|
||||
import core
|
||||
|
||||
# get logging object
|
||||
@@ -49,7 +47,7 @@ START_CODE = {
|
||||
0xB7 : 'sequence end',
|
||||
0xB8 : 'group of pictures',
|
||||
}
|
||||
for i in range(0x01,0xAF):
|
||||
for i in range(0x01, 0xAF):
|
||||
START_CODE[i] = 'slice_start_code'
|
||||
|
||||
##------------------------------------------------------------------------
|
||||
@@ -96,14 +94,14 @@ TS_SYNC = 0x47
|
||||
##------------------------------------------------------------------------
|
||||
FRAME_RATE = [
|
||||
0,
|
||||
24000.0/1001, ## 3-2 pulldown NTSC (CPB/Main Level)
|
||||
24, ## Film (CPB/Main Level)
|
||||
25, ## PAL/SECAM or 625/60 video
|
||||
30000.0/1001, ## NTSC (CPB/Main Level)
|
||||
30, ## drop-frame NTSC or component 525/60 (CPB/Main Level)
|
||||
50, ## double-rate PAL
|
||||
60000.0/1001, ## double-rate NTSC
|
||||
60, ## double-rate, drop-frame NTSC/component 525/60 video
|
||||
24000.0 / 1001, ## 3-2 pulldown NTSC (CPB/Main Level)
|
||||
24, ## Film (CPB/Main Level)
|
||||
25, ## PAL/SECAM or 625/60 video
|
||||
30000.0 / 1001, ## NTSC (CPB/Main Level)
|
||||
30, ## drop-frame NTSC or component 525/60 (CPB/Main Level)
|
||||
50, ## double-rate PAL
|
||||
60000.0 / 1001, ## double-rate NTSC
|
||||
60, ## double-rate, drop-frame NTSC/component 525/60 video
|
||||
]
|
||||
|
||||
##------------------------------------------------------------------------
|
||||
@@ -114,9 +112,9 @@ FRAME_RATE = [
|
||||
## it, a stream that doesn't adhere to one of these aspect ratios is
|
||||
## technically considered non-compliant.
|
||||
##------------------------------------------------------------------------
|
||||
ASPECT_RATIO = ( None, # Forbidden
|
||||
1.0, # 1/1 (VGA)
|
||||
4.0 / 3, # 4/3 (TV)
|
||||
ASPECT_RATIO = (None, # Forbidden
|
||||
1.0, # 1/1 (VGA)
|
||||
4.0 / 3, # 4/3 (TV)
|
||||
16.0 / 9, # 16/9 (Widescreen)
|
||||
2.21 # (Cinema)
|
||||
)
|
||||
@@ -131,7 +129,7 @@ class MPEG(core.AVContainer):
|
||||
no additional metadata like title, etc; only codecs, length and
|
||||
resolution is reported back.
|
||||
"""
|
||||
def __init__(self,file):
|
||||
def __init__(self, file):
|
||||
core.AVContainer.__init__(self)
|
||||
self.sequence_header_offset = 0
|
||||
self.mpeg_version = 2
|
||||
@@ -190,29 +188,29 @@ class MPEG(core.AVContainer):
|
||||
a.codec = ac
|
||||
|
||||
|
||||
def dxy(self,file):
|
||||
def dxy(self, file):
|
||||
"""
|
||||
get width and height of the video
|
||||
"""
|
||||
file.seek(self.sequence_header_offset+4,0)
|
||||
file.seek(self.sequence_header_offset + 4, 0)
|
||||
v = file.read(4)
|
||||
x = struct.unpack('>H',v[:2])[0] >> 4
|
||||
y = struct.unpack('>H',v[1:3])[0] & 0x0FFF
|
||||
return (x,y)
|
||||
x = struct.unpack('>H', v[:2])[0] >> 4
|
||||
y = struct.unpack('>H', v[1:3])[0] & 0x0FFF
|
||||
return (x, y)
|
||||
|
||||
|
||||
def framerate_aspect(self,file):
|
||||
def framerate_aspect(self, file):
|
||||
"""
|
||||
read framerate and aspect ratio
|
||||
"""
|
||||
file.seek(self.sequence_header_offset+7,0)
|
||||
v = struct.unpack( '>B', file.read(1) )[0]
|
||||
file.seek(self.sequence_header_offset + 7, 0)
|
||||
v = struct.unpack('>B', file.read(1))[0]
|
||||
try:
|
||||
fps = FRAME_RATE[v&0xf]
|
||||
fps = FRAME_RATE[v & 0xf]
|
||||
except IndexError:
|
||||
fps = None
|
||||
if v>>4 < len(ASPECT_RATIO):
|
||||
aspect = ASPECT_RATIO[v>>4]
|
||||
if v >> 4 < len(ASPECT_RATIO):
|
||||
aspect = ASPECT_RATIO[v >> 4]
|
||||
else:
|
||||
aspect = None
|
||||
return (fps, aspect)
|
||||
@@ -238,18 +236,18 @@ class MPEG(core.AVContainer):
|
||||
if pos == -1 or len(buffer) - pos < 5:
|
||||
buffer = buffer[-10:]
|
||||
continue
|
||||
ext = (ord(buffer[pos+4]) >> 4)
|
||||
ext = (ord(buffer[pos + 4]) >> 4)
|
||||
if ext == 8:
|
||||
pass
|
||||
elif ext == 1:
|
||||
if (ord(buffer[pos+5]) >> 3) & 1:
|
||||
if (ord(buffer[pos + 5]) >> 3) & 1:
|
||||
self._set('progressive', True)
|
||||
else:
|
||||
self._set('interlaced', True)
|
||||
return True
|
||||
else:
|
||||
log.debug('ext', ext)
|
||||
buffer = buffer[pos+4:]
|
||||
log.debug(u'ext: %r' % ext)
|
||||
buffer = buffer[pos + 4:]
|
||||
return False
|
||||
|
||||
|
||||
@@ -292,12 +290,12 @@ class MPEG(core.AVContainer):
|
||||
|
||||
## Some parts in the code are based on mpgtx (mpgtx.sf.net)
|
||||
|
||||
def bitrate(self,file):
|
||||
def bitrate(self, file):
|
||||
"""
|
||||
read the bitrate (most of the time broken)
|
||||
"""
|
||||
file.seek(self.sequence_header_offset+8,0)
|
||||
t,b = struct.unpack( '>HB', file.read(3) )
|
||||
file.seek(self.sequence_header_offset + 8, 0)
|
||||
t, b = struct.unpack('>HB', file.read(3))
|
||||
vrate = t << 2 | b >> 6
|
||||
return vrate * 400
|
||||
|
||||
@@ -309,9 +307,9 @@ class MPEG(core.AVContainer):
|
||||
if len(buffer) < 6:
|
||||
return None
|
||||
|
||||
highbit = (ord(buffer[0])&0x20)>>5
|
||||
highbit = (ord(buffer[0]) & 0x20) >> 5
|
||||
|
||||
low4Bytes= ((long(ord(buffer[0])) & 0x18) >> 3) << 30
|
||||
low4Bytes = ((long(ord(buffer[0])) & 0x18) >> 3) << 30
|
||||
low4Bytes |= (ord(buffer[0]) & 0x03) << 28
|
||||
low4Bytes |= ord(buffer[1]) << 20
|
||||
low4Bytes |= (ord(buffer[2]) & 0xF8) << 12
|
||||
@@ -319,10 +317,10 @@ class MPEG(core.AVContainer):
|
||||
low4Bytes |= ord(buffer[3]) << 5
|
||||
low4Bytes |= (ord(buffer[4])) >> 3
|
||||
|
||||
sys_clock_ref=(ord(buffer[4]) & 0x3) << 7
|
||||
sys_clock_ref|=(ord(buffer[5]) >> 1)
|
||||
sys_clock_ref = (ord(buffer[4]) & 0x3) << 7
|
||||
sys_clock_ref |= (ord(buffer[5]) >> 1)
|
||||
|
||||
return (long(highbit * (1<<16) * (1<<16)) + low4Bytes) / 90000
|
||||
return (long(highbit * (1 << 16) * (1 << 16)) + low4Bytes) / 90000
|
||||
|
||||
|
||||
def ReadSCRMpeg1(self, buffer):
|
||||
@@ -340,7 +338,7 @@ class MPEG(core.AVContainer):
|
||||
low4Bytes |= ord(buffer[3]) << 7;
|
||||
low4Bytes |= ord(buffer[4]) >> 1;
|
||||
|
||||
return (long(highbit) * (1<<16) * (1<<16) + low4Bytes) / 90000;
|
||||
return (long(highbit) * (1 << 16) * (1 << 16) + low4Bytes) / 90000;
|
||||
|
||||
|
||||
def ReadPTS(self, buffer):
|
||||
@@ -350,7 +348,7 @@ class MPEG(core.AVContainer):
|
||||
high = ((ord(buffer[0]) & 0xF) >> 1)
|
||||
med = (ord(buffer[1]) << 7) + (ord(buffer[2]) >> 1)
|
||||
low = (ord(buffer[3]) << 7) + (ord(buffer[4]) >> 1)
|
||||
return ((long(high) << 30 ) + (med << 15) + low) / 90000
|
||||
return ((long(high) << 30) + (med << 15) + low) / 90000
|
||||
|
||||
|
||||
def ReadHeader(self, buffer, offset):
|
||||
@@ -358,25 +356,25 @@ class MPEG(core.AVContainer):
|
||||
Handle MPEG header in buffer on position offset
|
||||
Return None on error, new offset or 0 if the new offset can't be scanned
|
||||
"""
|
||||
if buffer[offset:offset+3] != '\x00\x00\x01':
|
||||
if buffer[offset:offset + 3] != '\x00\x00\x01':
|
||||
return None
|
||||
|
||||
id = ord(buffer[offset+3])
|
||||
id = ord(buffer[offset + 3])
|
||||
|
||||
if id == PADDING_PKT:
|
||||
return offset + (ord(buffer[offset+4]) << 8) + \
|
||||
ord(buffer[offset+5]) + 6
|
||||
return offset + (ord(buffer[offset + 4]) << 8) + \
|
||||
ord(buffer[offset + 5]) + 6
|
||||
|
||||
if id == PACK_PKT:
|
||||
if ord(buffer[offset+4]) & 0xF0 == 0x20:
|
||||
if ord(buffer[offset + 4]) & 0xF0 == 0x20:
|
||||
self.type = 'MPEG-1 Video'
|
||||
self.get_time = self.ReadSCRMpeg1
|
||||
self.mpeg_version = 1
|
||||
return offset + 12
|
||||
elif (ord(buffer[offset+4]) & 0xC0) == 0x40:
|
||||
elif (ord(buffer[offset + 4]) & 0xC0) == 0x40:
|
||||
self.type = 'MPEG-2 Video'
|
||||
self.get_time = self.ReadSCRMpeg2
|
||||
return offset + (ord(buffer[offset+13]) & 0x07) + 14
|
||||
return offset + (ord(buffer[offset + 13]) & 0x07) + 14
|
||||
else:
|
||||
# I have no idea what just happened, but for some DVB
|
||||
# recordings done with mencoder this points to a
|
||||
@@ -412,10 +410,10 @@ class MPEG(core.AVContainer):
|
||||
|
||||
if id in [PRIVATE_STREAM1, PRIVATE_STREAM2]:
|
||||
# private stream. we don't know, but maybe we can guess later
|
||||
add = ord(buffer[offset+8])
|
||||
add = ord(buffer[offset + 8])
|
||||
# if (ord(buffer[offset+6]) & 4) or 1:
|
||||
# id = ord(buffer[offset+10+add])
|
||||
if buffer[offset+11+add:offset+15+add].find('\x0b\x77') != -1:
|
||||
if buffer[offset + 11 + add:offset + 15 + add].find('\x0b\x77') != -1:
|
||||
# AC3 stream
|
||||
for a in self.audio:
|
||||
if a.id == id:
|
||||
@@ -442,18 +440,18 @@ class MPEG(core.AVContainer):
|
||||
This MPEG starts with a sequence of 0x00 followed by a PACK Header
|
||||
http://dvd.sourceforge.net/dvdinfo/packhdr.html
|
||||
"""
|
||||
file.seek(0,0)
|
||||
file.seek(0, 0)
|
||||
buffer = file.read(10000)
|
||||
offset = 0
|
||||
|
||||
# seek until the 0 byte stop
|
||||
while offset < len(buffer)-100 and buffer[offset] == '\0':
|
||||
while offset < len(buffer) - 100 and buffer[offset] == '\0':
|
||||
offset += 1
|
||||
offset -= 2
|
||||
|
||||
# test for mpeg header 0x00 0x00 0x01
|
||||
header = '\x00\x00\x01%s' % chr(PACK_PKT)
|
||||
if offset < 0 or not buffer[offset:offset+4] == header:
|
||||
if offset < 0 or not buffer[offset:offset + 4] == header:
|
||||
if not force:
|
||||
return 0
|
||||
# brute force and try to find the pack header in the first
|
||||
@@ -470,9 +468,9 @@ class MPEG(core.AVContainer):
|
||||
self.ReadHeader(buffer, offset)
|
||||
|
||||
# store first timestamp
|
||||
self.start = self.get_time(buffer[offset+4:])
|
||||
self.start = self.get_time(buffer[offset + 4:])
|
||||
while len(buffer) > offset + 1000 and \
|
||||
buffer[offset:offset+3] == '\x00\x00\x01':
|
||||
buffer[offset:offset + 3] == '\x00\x00\x01':
|
||||
# read the mpeg header
|
||||
new_offset = self.ReadHeader(buffer, offset)
|
||||
|
||||
@@ -486,12 +484,12 @@ class MPEG(core.AVContainer):
|
||||
|
||||
# skip padding 0 before a new header
|
||||
while len(buffer) > offset + 10 and \
|
||||
not ord(buffer[offset+2]):
|
||||
not ord(buffer[offset + 2]):
|
||||
offset += 1
|
||||
|
||||
else:
|
||||
# seek to new header by brute force
|
||||
offset += buffer[offset+4:].find('\x00\x00\x01') + 4
|
||||
offset += buffer[offset + 4:].find('\x00\x00\x01') + 4
|
||||
|
||||
# fill in values for support functions:
|
||||
self.__seek_size__ = 1000000
|
||||
@@ -555,15 +553,15 @@ class MPEG(core.AVContainer):
|
||||
self.video[-1]._set('id', id)
|
||||
|
||||
# new mpeg starting
|
||||
if buffer[header_length+9:header_length+13] == \
|
||||
if buffer[header_length + 9:header_length + 13] == \
|
||||
'\x00\x00\x01\xB3' and not self.sequence_header_offset:
|
||||
# yes, remember offset for later use
|
||||
self.sequence_header_offset = offset + header_length+9
|
||||
self.sequence_header_offset = offset + header_length + 9
|
||||
elif ord(buffer[3]) == 189 or ord(buffer[3]) == 191:
|
||||
# private stream. we don't know, but maybe we can guess later
|
||||
id = id or ord(buffer[3]) & 0xF
|
||||
if align and \
|
||||
buffer[header_length+9:header_length+11] == '\x0b\x77':
|
||||
buffer[header_length + 9:header_length + 11] == '\x0b\x77':
|
||||
# AC3 stream
|
||||
for a in self.audio:
|
||||
if a.id == id:
|
||||
@@ -581,7 +579,7 @@ class MPEG(core.AVContainer):
|
||||
|
||||
if ptsdts and ptsdts == ord(buffer[9]) >> 4:
|
||||
if ord(buffer[9]) >> 4 != ptsdts:
|
||||
log.warning('WARNING: bad PTS/DTS, please contact us')
|
||||
log.warning(u'WARNING: bad PTS/DTS, please contact us')
|
||||
return packet_length, None
|
||||
|
||||
# timestamp = self.ReadPTS(buffer[9:14])
|
||||
@@ -595,8 +593,8 @@ class MPEG(core.AVContainer):
|
||||
|
||||
|
||||
def isPES(self, file):
|
||||
log.info('trying mpeg-pes scan')
|
||||
file.seek(0,0)
|
||||
log.info(u'trying mpeg-pes scan')
|
||||
file.seek(0, 0)
|
||||
buffer = file.read(3)
|
||||
|
||||
# header (also valid for all mpegs)
|
||||
@@ -613,7 +611,7 @@ class MPEG(core.AVContainer):
|
||||
return 0
|
||||
if timestamp != None and not hasattr(self, 'start'):
|
||||
self.get_time = self.ReadPTS
|
||||
bpos = buffer[offset+timestamp:offset+timestamp+5]
|
||||
bpos = buffer[offset + timestamp:offset + timestamp + 5]
|
||||
self.start = self.get_time(bpos)
|
||||
if self.sequence_header_offset and hasattr(self, 'start'):
|
||||
# we have all informations we need
|
||||
@@ -702,13 +700,13 @@ class MPEG(core.AVContainer):
|
||||
# Transport Stream ===============================================
|
||||
|
||||
def isTS(self, file):
|
||||
file.seek(0,0)
|
||||
file.seek(0, 0)
|
||||
|
||||
buffer = file.read(TS_PACKET_LENGTH * 2)
|
||||
c = 0
|
||||
|
||||
while c + TS_PACKET_LENGTH < len(buffer):
|
||||
if ord(buffer[c]) == ord(buffer[c+TS_PACKET_LENGTH]) == TS_SYNC:
|
||||
if ord(buffer[c]) == ord(buffer[c + TS_PACKET_LENGTH]) == TS_SYNC:
|
||||
break
|
||||
c += 1
|
||||
else:
|
||||
@@ -718,7 +716,7 @@ class MPEG(core.AVContainer):
|
||||
self.type = 'MPEG-TS'
|
||||
|
||||
while c + TS_PACKET_LENGTH < len(buffer):
|
||||
start = ord(buffer[c+1]) & 0x40
|
||||
start = ord(buffer[c + 1]) & 0x40
|
||||
# maybe load more into the buffer
|
||||
if c + 2 * TS_PACKET_LENGTH > len(buffer) and c < 500000:
|
||||
buffer += file.read(10000)
|
||||
@@ -728,30 +726,30 @@ class MPEG(core.AVContainer):
|
||||
c += TS_PACKET_LENGTH
|
||||
continue
|
||||
|
||||
tsid = ((ord(buffer[c+1]) & 0x3F) << 8) + ord(buffer[c+2])
|
||||
adapt = (ord(buffer[c+3]) & 0x30) >> 4
|
||||
tsid = ((ord(buffer[c + 1]) & 0x3F) << 8) + ord(buffer[c + 2])
|
||||
adapt = (ord(buffer[c + 3]) & 0x30) >> 4
|
||||
|
||||
offset = 4
|
||||
if adapt & 0x02:
|
||||
# meta info present, skip it for now
|
||||
adapt_len = ord(buffer[c+offset])
|
||||
adapt_len = ord(buffer[c + offset])
|
||||
offset += adapt_len + 1
|
||||
|
||||
if not ord(buffer[c+1]) & 0x40:
|
||||
if not ord(buffer[c + 1]) & 0x40:
|
||||
# no new pes or psi in stream payload starting
|
||||
pass
|
||||
elif adapt & 0x01:
|
||||
# PES
|
||||
timestamp = self.ReadPESHeader(c+offset, buffer[c+offset:],
|
||||
timestamp = self.ReadPESHeader(c + offset, buffer[c + offset:],
|
||||
tsid)[1]
|
||||
if timestamp != None:
|
||||
if not hasattr(self, 'start'):
|
||||
self.get_time = self.ReadPTS
|
||||
timestamp = c + offset + timestamp
|
||||
self.start = self.get_time(buffer[timestamp:timestamp+5])
|
||||
self.start = self.get_time(buffer[timestamp:timestamp + 5])
|
||||
elif not hasattr(self, 'audio_ok'):
|
||||
timestamp = c + offset + timestamp
|
||||
start = self.get_time(buffer[timestamp:timestamp+5])
|
||||
start = self.get_time(buffer[timestamp:timestamp + 5])
|
||||
if start is not None and self.start is not None and \
|
||||
abs(start - self.start) < 10:
|
||||
# looks ok
|
||||
@@ -759,7 +757,7 @@ class MPEG(core.AVContainer):
|
||||
else:
|
||||
# timestamp broken
|
||||
del self.start
|
||||
log.warning('Timestamp error, correcting')
|
||||
log.warning(u'Timestamp error, correcting')
|
||||
|
||||
if hasattr(self, 'start') and self.start and \
|
||||
self.sequence_header_offset and self.video and self.audio:
|
||||
@@ -786,31 +784,31 @@ class MPEG(core.AVContainer):
|
||||
c = 0
|
||||
|
||||
while c + TS_PACKET_LENGTH < len(buffer):
|
||||
if ord(buffer[c]) == ord(buffer[c+TS_PACKET_LENGTH]) == TS_SYNC:
|
||||
if ord(buffer[c]) == ord(buffer[c + TS_PACKET_LENGTH]) == TS_SYNC:
|
||||
break
|
||||
c += 1
|
||||
else:
|
||||
return None
|
||||
|
||||
while c + TS_PACKET_LENGTH < len(buffer):
|
||||
start = ord(buffer[c+1]) & 0x40
|
||||
start = ord(buffer[c + 1]) & 0x40
|
||||
if not start:
|
||||
c += TS_PACKET_LENGTH
|
||||
continue
|
||||
|
||||
tsid = ((ord(buffer[c+1]) & 0x3F) << 8) + ord(buffer[c+2])
|
||||
adapt = (ord(buffer[c+3]) & 0x30) >> 4
|
||||
tsid = ((ord(buffer[c + 1]) & 0x3F) << 8) + ord(buffer[c + 2])
|
||||
adapt = (ord(buffer[c + 3]) & 0x30) >> 4
|
||||
|
||||
offset = 4
|
||||
if adapt & 0x02:
|
||||
# meta info present, skip it for now
|
||||
offset += ord(buffer[c+offset]) + 1
|
||||
offset += ord(buffer[c + offset]) + 1
|
||||
|
||||
if adapt & 0x01:
|
||||
timestamp = self.ReadPESHeader(c+offset, buffer[c+offset:], tsid)[1]
|
||||
timestamp = self.ReadPESHeader(c + offset, buffer[c + offset:], tsid)[1]
|
||||
if timestamp is None:
|
||||
# this should not happen
|
||||
log.error('bad TS')
|
||||
log.error(u'bad TS')
|
||||
return None
|
||||
return c + offset + timestamp
|
||||
c += TS_PACKET_LENGTH
|
||||
@@ -841,7 +839,7 @@ class MPEG(core.AVContainer):
|
||||
if pos == None:
|
||||
break
|
||||
end = self.get_time(buffer[pos:]) or end
|
||||
buffer = buffer[pos+100:]
|
||||
buffer = buffer[pos + 100:]
|
||||
|
||||
file.close()
|
||||
return end
|
||||
@@ -855,7 +853,7 @@ class MPEG(core.AVContainer):
|
||||
if end == None or self.start == None:
|
||||
return None
|
||||
if self.start > end:
|
||||
return int(((long(1) << 33) - 1 ) / 90000) - self.start + end
|
||||
return int(((long(1) << 33) - 1) / 90000) - self.start + end
|
||||
return end - self.start
|
||||
|
||||
|
||||
@@ -897,7 +895,7 @@ class MPEG(core.AVContainer):
|
||||
return 0
|
||||
|
||||
file = open(self.filename)
|
||||
log.debug('scanning file...')
|
||||
log.debug(u'scanning file...')
|
||||
while 1:
|
||||
file.seek(self.__seek_size__ * 10, 1)
|
||||
buffer = file.read(self.__sample_size__)
|
||||
@@ -906,10 +904,10 @@ class MPEG(core.AVContainer):
|
||||
pos = self.__search__(buffer)
|
||||
if pos == None:
|
||||
continue
|
||||
log.debug('buffer position: %s' % self.get_time(buffer[pos:]))
|
||||
log.debug(u'buffer position: %r' % self.get_time(buffer[pos:]))
|
||||
|
||||
file.close()
|
||||
log.debug('done scanning file')
|
||||
log.debug(u'done scanning file')
|
||||
|
||||
|
||||
Parser = MPEG
|
||||
+29
-31
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -17,9 +17,7 @@
|
||||
# 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 struct
|
||||
@@ -27,7 +25,7 @@ import re
|
||||
import stat
|
||||
import os
|
||||
import logging
|
||||
from exceptions import *
|
||||
from exceptions import ParseError
|
||||
import core
|
||||
|
||||
# get logging object
|
||||
@@ -82,7 +80,7 @@ class Ogm(core.AVContainer):
|
||||
|
||||
# seek to the end of the stream, to avoid scanning the whole file
|
||||
if (os.stat(file.name)[stat.ST_SIZE] > 50000):
|
||||
file.seek(os.stat(file.name)[stat.ST_SIZE]-49000)
|
||||
file.seek(os.stat(file.name)[stat.ST_SIZE] - 49000)
|
||||
|
||||
# read the rest of the file into a buffer
|
||||
h = file.read()
|
||||
@@ -147,21 +145,21 @@ class Ogm(core.AVContainer):
|
||||
self._appendtable('VORBISCOMMENT', header)
|
||||
|
||||
|
||||
def _parseOGGS(self,file):
|
||||
def _parseOGGS(self, file):
|
||||
h = file.read(27)
|
||||
if len(h) == 0:
|
||||
# Regular File end
|
||||
return None, None
|
||||
elif len(h) < 27:
|
||||
log.debug("%d Bytes of Garbage found after End." % len(h))
|
||||
log.debug(u'%d Bytes of Garbage found after End.' % len(h))
|
||||
return None, None
|
||||
if h[:4] != "OggS":
|
||||
log.debug("Invalid Ogg")
|
||||
log.debug(u'Invalid Ogg')
|
||||
raise ParseError()
|
||||
|
||||
version = ord(h[4])
|
||||
if version != 0:
|
||||
log.debug("Unsupported OGG/OGM Version %d." % version)
|
||||
log.debug(u'Unsupported OGG/OGM Version %d' % version)
|
||||
return None, None
|
||||
|
||||
head = struct.unpack('<BQIIIB', h[5:])
|
||||
@@ -178,13 +176,13 @@ class Ogm(core.AVContainer):
|
||||
h = file.read(1)
|
||||
packettype = ord(h[0]) & PACKET_TYPE_BITS
|
||||
if packettype == PACKET_TYPE_HEADER:
|
||||
h += file.read(nextlen-1)
|
||||
h += file.read(nextlen - 1)
|
||||
self._parseHeader(h, granulepos)
|
||||
elif packettype == PACKED_TYPE_METADATA:
|
||||
h += file.read(nextlen-1)
|
||||
h += file.read(nextlen - 1)
|
||||
self._parseMeta(h)
|
||||
else:
|
||||
file.seek(nextlen-1,1)
|
||||
file.seek(nextlen - 1, 1)
|
||||
if len(self.all_streams) > serial:
|
||||
stream = self.all_streams[serial]
|
||||
if hasattr(stream, 'samplerate') and \
|
||||
@@ -197,27 +195,27 @@ class Ogm(core.AVContainer):
|
||||
return granulepos, nextlen + 27 + pageSegCount
|
||||
|
||||
|
||||
def _parseMeta(self,h):
|
||||
def _parseMeta(self, h):
|
||||
flags = ord(h[0])
|
||||
headerlen = len(h)
|
||||
if headerlen >= 7 and h[1:7] == 'vorbis':
|
||||
header = {}
|
||||
nextlen, self.encoder = self._extractHeaderString(h[7:])
|
||||
numItems = struct.unpack('<I',h[7+nextlen:7+nextlen+4])[0]
|
||||
start = 7+4+nextlen
|
||||
for i in range(numItems):
|
||||
numItems = struct.unpack('<I', h[7 + nextlen:7 + nextlen + 4])[0]
|
||||
start = 7 + 4 + nextlen
|
||||
for _ in range(numItems):
|
||||
(nextlen, s) = self._extractHeaderString(h[start:])
|
||||
start += nextlen
|
||||
if s:
|
||||
a = re.split('=',s)
|
||||
header[(a[0]).upper()]=a[1]
|
||||
a = re.split('=', s)
|
||||
header[(a[0]).upper()] = a[1]
|
||||
# Put Header fields into info fields
|
||||
self.type = 'OGG Vorbis'
|
||||
self.subtype = ''
|
||||
self.all_header.append(header)
|
||||
|
||||
|
||||
def _parseHeader(self,header,granule):
|
||||
def _parseHeader(self, header, granule):
|
||||
headerlen = len(header)
|
||||
flags = ord(header[0])
|
||||
|
||||
@@ -225,7 +223,7 @@ class Ogm(core.AVContainer):
|
||||
ai = core.AudioStream()
|
||||
ai.version, ai.channels, ai.samplerate, bitrate_max, ai.bitrate, \
|
||||
bitrate_min, blocksize, framing = \
|
||||
struct.unpack('<IBIiiiBB',header[7:7+23])
|
||||
struct.unpack('<IBIiiiBB', header[7:7 + 23])
|
||||
ai.codec = 'Vorbis'
|
||||
#ai.granule = granule
|
||||
#ai.length = granule / ai.samplerate
|
||||
@@ -250,12 +248,12 @@ class Ogm(core.AVContainer):
|
||||
self.all_streams.append(vi)
|
||||
|
||||
elif flags & PACKET_TYPE_BITS == PACKET_TYPE_HEADER and \
|
||||
headerlen >= struct.calcsize(STREAM_HEADER_VIDEO)+1:
|
||||
headerlen >= struct.calcsize(STREAM_HEADER_VIDEO) + 1:
|
||||
# New Directshow Format
|
||||
htype = header[1:9]
|
||||
|
||||
if htype[:5] == 'video':
|
||||
sh = header[9:struct.calcsize(STREAM_HEADER_VIDEO)+9]
|
||||
sh = header[9:struct.calcsize(STREAM_HEADER_VIDEO) + 9]
|
||||
streamheader = struct.unpack(STREAM_HEADER_VIDEO, sh)
|
||||
vi = core.VideoStream()
|
||||
(type, ssize, timeunit, samplerate, vi.length, buffersize, \
|
||||
@@ -270,13 +268,13 @@ class Ogm(core.AVContainer):
|
||||
self.all_streams.append(vi)
|
||||
|
||||
elif htype[:5] == 'audio':
|
||||
sha = header[9:struct.calcsize(STREAM_HEADER_AUDIO)+9]
|
||||
sha = header[9:struct.calcsize(STREAM_HEADER_AUDIO) + 9]
|
||||
streamheader = struct.unpack(STREAM_HEADER_AUDIO, sha)
|
||||
ai = core.AudioStream()
|
||||
(type, ssize, timeunit, ai.samplerate, ai.length, buffersize, \
|
||||
ai.bitrate, ai.channels, bloc, ai.bitrate) = streamheader
|
||||
self.samplerate = ai.samplerate
|
||||
log.debug("Samplerate %d" % self.samplerate)
|
||||
log.debug(u'Samplerate %d' % self.samplerate)
|
||||
self.audio.append(ai)
|
||||
self.all_streams.append(ai)
|
||||
|
||||
@@ -287,15 +285,15 @@ class Ogm(core.AVContainer):
|
||||
self.all_streams.append(subtitle)
|
||||
|
||||
else:
|
||||
log.debug("Unknown Header")
|
||||
log.debug(u'Unknown Header')
|
||||
|
||||
|
||||
def _extractHeaderString(self,header):
|
||||
def _extractHeaderString(self, header):
|
||||
len = struct.unpack('<I', header[:4])[0]
|
||||
try:
|
||||
return (len+4,unicode(header[4:4+len], 'utf-8'))
|
||||
return (len + 4, unicode(header[4:4 + len], 'utf-8'))
|
||||
except (KeyError, IndexError, UnicodeDecodeError):
|
||||
return (len+4,None)
|
||||
return (len + 4, None)
|
||||
|
||||
|
||||
Parser = Ogm
|
||||
+39
-41
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -17,14 +17,12 @@
|
||||
# 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 struct
|
||||
import logging
|
||||
from exceptions import *
|
||||
from exceptions import ParseError
|
||||
import core
|
||||
|
||||
# http://www.pcisys.net/~melanson/codecs/rmff.htm
|
||||
@@ -34,13 +32,13 @@ import core
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class RealVideo(core.AVContainer):
|
||||
def __init__(self,file):
|
||||
def __init__(self, file):
|
||||
core.AVContainer.__init__(self)
|
||||
self.mime = 'video/real'
|
||||
self.type = 'Real Video'
|
||||
h = file.read(10)
|
||||
try:
|
||||
(object_id,object_size,object_version) = struct.unpack('>4sIH',h)
|
||||
(object_id, object_size, object_version) = struct.unpack('>4sIH', h)
|
||||
except struct.error:
|
||||
# EOF.
|
||||
raise ParseError()
|
||||
@@ -49,47 +47,47 @@ class RealVideo(core.AVContainer):
|
||||
raise ParseError()
|
||||
|
||||
file_version, num_headers = struct.unpack('>II', file.read(8))
|
||||
log.debug("size: %d, ver: %d, headers: %d" % \
|
||||
(object_size, file_version,num_headers))
|
||||
for i in range(0,num_headers):
|
||||
log.debug(u'size: %d, ver: %d, headers: %d' % \
|
||||
(object_size, file_version, num_headers))
|
||||
for _ in range(0, num_headers):
|
||||
try:
|
||||
oi = struct.unpack('>4sIH',file.read(10))
|
||||
oi = struct.unpack('>4sIH', file.read(10))
|
||||
except (struct.error, IOError):
|
||||
# Header data we expected wasn't there. File may be
|
||||
# only partially complete.
|
||||
break
|
||||
|
||||
if object_id == 'DATA' and oi[0] != 'INDX':
|
||||
log.debug('INDX chunk expected after DATA but not found -- file corrupt')
|
||||
log.debug(u'INDX chunk expected after DATA but not found -- file corrupt')
|
||||
break
|
||||
|
||||
(object_id,object_size,object_version) = oi
|
||||
(object_id, object_size, object_version) = oi
|
||||
if object_id == 'DATA':
|
||||
# Seek over the data chunk rather than reading it in.
|
||||
file.seek(object_size - 10, 1)
|
||||
else:
|
||||
self._read_header(object_id, file.read(object_size-10))
|
||||
log.debug("%s [%d]" % (object_id,object_size-10))
|
||||
self._read_header(object_id, file.read(object_size - 10))
|
||||
log.debug(u'%r [%d]' % (object_id, object_size - 10))
|
||||
# Read all the following headers
|
||||
|
||||
|
||||
def _read_header(self,object_id,s):
|
||||
def _read_header(self, object_id, s):
|
||||
if object_id == 'PROP':
|
||||
prop = struct.unpack('>9IHH', s)
|
||||
log.debug(prop)
|
||||
log.debug(u'PROP: %r' % prop)
|
||||
if object_id == 'MDPR':
|
||||
mdpr = struct.unpack('>H7I', s[:30])
|
||||
log.debug(mdpr)
|
||||
self.length = mdpr[7]/1000.0
|
||||
log.debug(u'MDPR: %r' % mdpr)
|
||||
self.length = mdpr[7] / 1000.0
|
||||
(stream_name_size,) = struct.unpack('>B', s[30:31])
|
||||
stream_name = s[31:31+stream_name_size]
|
||||
pos = 31+stream_name_size
|
||||
(mime_type_size,) = struct.unpack('>B', s[pos:pos+1])
|
||||
mime = s[pos+1:pos+1+mime_type_size]
|
||||
pos += mime_type_size+1
|
||||
(type_specific_len,) = struct.unpack('>I', s[pos:pos+4])
|
||||
type_specific = s[pos+4:pos+4+type_specific_len]
|
||||
pos += 4+type_specific_len
|
||||
stream_name = s[31:31 + stream_name_size]
|
||||
pos = 31 + stream_name_size
|
||||
(mime_type_size,) = struct.unpack('>B', s[pos:pos + 1])
|
||||
mime = s[pos + 1:pos + 1 + mime_type_size]
|
||||
pos += mime_type_size + 1
|
||||
(type_specific_len,) = struct.unpack('>I', s[pos:pos + 4])
|
||||
type_specific = s[pos + 4:pos + 4 + type_specific_len]
|
||||
pos += 4 + type_specific_len
|
||||
if mime[:5] == 'audio':
|
||||
ai = core.AudioStream()
|
||||
ai.id = mdpr[0]
|
||||
@@ -101,20 +99,20 @@ class RealVideo(core.AVContainer):
|
||||
vi.bitrate = mdpr[2]
|
||||
self.video.append(vi)
|
||||
else:
|
||||
log.debug("Unknown: %s" % mime)
|
||||
log.debug(u'Unknown: %r' % mime)
|
||||
if object_id == 'CONT':
|
||||
pos = 0
|
||||
(title_len,) = struct.unpack('>H', s[pos:pos+2])
|
||||
self.title = s[2:title_len+2]
|
||||
pos += title_len+2
|
||||
(author_len,) = struct.unpack('>H', s[pos:pos+2])
|
||||
self.artist = s[pos+2:pos+author_len+2]
|
||||
pos += author_len+2
|
||||
(copyright_len,) = struct.unpack('>H', s[pos:pos+2])
|
||||
self.copyright = s[pos+2:pos+copyright_len+2]
|
||||
pos += copyright_len+2
|
||||
(comment_len,) = struct.unpack('>H', s[pos:pos+2])
|
||||
self.comment = s[pos+2:pos+comment_len+2]
|
||||
(title_len,) = struct.unpack('>H', s[pos:pos + 2])
|
||||
self.title = s[2:title_len + 2]
|
||||
pos += title_len + 2
|
||||
(author_len,) = struct.unpack('>H', s[pos:pos + 2])
|
||||
self.artist = s[pos + 2:pos + author_len + 2]
|
||||
pos += author_len + 2
|
||||
(copyright_len,) = struct.unpack('>H', s[pos:pos + 2])
|
||||
self.copyright = s[pos + 2:pos + copyright_len + 2]
|
||||
pos += copyright_len + 2
|
||||
(comment_len,) = struct.unpack('>H', s[pos:pos + 2])
|
||||
self.comment = s[pos + 2:pos + comment_len + 2]
|
||||
|
||||
|
||||
Parser = RealVideo
|
||||
+85
-87
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright (C) 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2003-2006 Thomas Schueppel <stain@acm.org>
|
||||
# Copyright 2003-2006 Dirk Meyer <dischi@freevo.org>
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -17,9 +17,7 @@
|
||||
# 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 os
|
||||
@@ -27,7 +25,7 @@ import struct
|
||||
import string
|
||||
import logging
|
||||
import time
|
||||
from exceptions import *
|
||||
from exceptions import ParseError
|
||||
import core
|
||||
|
||||
# get logging object
|
||||
@@ -70,7 +68,7 @@ class Riff(core.AVContainer):
|
||||
"""
|
||||
table_mapping = { 'AVIINFO' : AVIINFO }
|
||||
|
||||
def __init__(self,file):
|
||||
def __init__(self, file):
|
||||
core.AVContainer.__init__(self)
|
||||
# read the header
|
||||
h = file.read(12)
|
||||
@@ -90,12 +88,12 @@ class Riff(core.AVContainer):
|
||||
while self._parseRIFFChunk(file):
|
||||
pass
|
||||
except IOError:
|
||||
log.exception('error in file, stop parsing')
|
||||
log.exception(u'error in file, stop parsing')
|
||||
|
||||
self._find_subtitles(file.name)
|
||||
|
||||
if not self.has_idx and isinstance(self, core.AVContainer):
|
||||
log.debug('WARNING: avi has no index')
|
||||
log.debug(u'WARNING: avi has no index')
|
||||
self._set('corrupt', True)
|
||||
|
||||
|
||||
@@ -104,9 +102,9 @@ class Riff(core.AVContainer):
|
||||
Search for subtitle files. Right now only VobSub is supported
|
||||
"""
|
||||
base = os.path.splitext(filename)[0]
|
||||
if os.path.isfile(base+'.idx') and \
|
||||
(os.path.isfile(base+'.sub') or os.path.isfile(base+'.rar')):
|
||||
file = open(base+'.idx')
|
||||
if os.path.isfile(base + '.idx') and \
|
||||
(os.path.isfile(base + '.sub') or os.path.isfile(base + '.rar')):
|
||||
file = open(base + '.idx')
|
||||
if file.readline().find('VobSub index file') > 0:
|
||||
for line in file.readlines():
|
||||
if line.find('id') == 0:
|
||||
@@ -117,10 +115,10 @@ class Riff(core.AVContainer):
|
||||
file.close()
|
||||
|
||||
|
||||
def _parseAVIH(self,t):
|
||||
def _parseAVIH(self, t):
|
||||
retval = {}
|
||||
v = struct.unpack('<IIIIIIIIIIIIII',t[0:56])
|
||||
( retval['dwMicroSecPerFrame'],
|
||||
v = struct.unpack('<IIIIIIIIIIIIII', t[0:56])
|
||||
(retval['dwMicroSecPerFrame'],
|
||||
retval['dwMaxBytesPerSec'],
|
||||
retval['dwPaddingGranularity'],
|
||||
retval['dwFlags'],
|
||||
@@ -133,22 +131,22 @@ class Riff(core.AVContainer):
|
||||
retval['dwScale'],
|
||||
retval['dwRate'],
|
||||
retval['dwStart'],
|
||||
retval['dwLength'] ) = v
|
||||
retval['dwLength']) = v
|
||||
if retval['dwMicroSecPerFrame'] == 0:
|
||||
log.warning("ERROR: Corrupt AVI")
|
||||
log.warning(u'ERROR: Corrupt AVI')
|
||||
raise ParseError()
|
||||
|
||||
return retval
|
||||
|
||||
|
||||
def _parseSTRH(self,t):
|
||||
def _parseSTRH(self, t):
|
||||
retval = {}
|
||||
retval['fccType'] = t[0:4]
|
||||
log.debug("_parseSTRH(%s) : %d bytes" % (retval['fccType'], len(t)))
|
||||
log.debug(u'_parseSTRH(%r) : %d bytes' % (retval['fccType'], len(t)))
|
||||
if retval['fccType'] != 'auds':
|
||||
retval['fccHandler'] = t[4:8]
|
||||
v = struct.unpack('<IHHIIIIIIIII',t[8:52])
|
||||
( retval['dwFlags'],
|
||||
v = struct.unpack('<IHHIIIIIIIII', t[8:52])
|
||||
(retval['dwFlags'],
|
||||
retval['wPriority'],
|
||||
retval['wLanguage'],
|
||||
retval['dwInitialFrames'],
|
||||
@@ -159,11 +157,11 @@ class Riff(core.AVContainer):
|
||||
retval['dwSuggestedBufferSize'],
|
||||
retval['dwQuality'],
|
||||
retval['dwSampleSize'],
|
||||
retval['rcFrame'] ) = v
|
||||
retval['rcFrame']) = v
|
||||
else:
|
||||
try:
|
||||
v = struct.unpack('<IHHIIIIIIIII',t[8:52])
|
||||
( retval['dwFlags'],
|
||||
v = struct.unpack('<IHHIIIIIIIII', t[8:52])
|
||||
(retval['dwFlags'],
|
||||
retval['wPriority'],
|
||||
retval['wLanguage'],
|
||||
retval['dwInitialFrames'],
|
||||
@@ -174,7 +172,7 @@ class Riff(core.AVContainer):
|
||||
retval['dwSuggestedBufferSize'],
|
||||
retval['dwQuality'],
|
||||
retval['dwSampleSize'],
|
||||
retval['rcFrame'] ) = v
|
||||
retval['rcFrame']) = v
|
||||
self.delay = float(retval['dwStart']) / \
|
||||
(float(retval['dwRate']) / retval['dwScale'])
|
||||
except (KeyError, IndexError, ValueError, ZeroDivisionError):
|
||||
@@ -183,12 +181,12 @@ class Riff(core.AVContainer):
|
||||
return retval
|
||||
|
||||
|
||||
def _parseSTRF(self,t,strh):
|
||||
def _parseSTRF(self, t, strh):
|
||||
fccType = strh['fccType']
|
||||
retval = {}
|
||||
if fccType == 'auds':
|
||||
v = struct.unpack('<HHHHHH',t[0:12])
|
||||
( retval['wFormatTag'],
|
||||
v = struct.unpack('<HHHHHH', t[0:12])
|
||||
(retval['wFormatTag'],
|
||||
retval['nChannels'],
|
||||
retval['nSamplesPerSec'],
|
||||
retval['nAvgBytesPerSec'],
|
||||
@@ -209,18 +207,18 @@ class Riff(core.AVContainer):
|
||||
ai.codec = retval['wFormatTag']
|
||||
self.audio.append(ai)
|
||||
elif fccType == 'vids':
|
||||
v = struct.unpack('<IIIHH',t[0:16])
|
||||
( retval['biSize'],
|
||||
v = struct.unpack('<IIIHH', t[0:16])
|
||||
(retval['biSize'],
|
||||
retval['biWidth'],
|
||||
retval['biHeight'],
|
||||
retval['biPlanes'],
|
||||
retval['biBitCount'] ) = v
|
||||
v = struct.unpack('IIIII',t[20:40])
|
||||
( retval['biSizeImage'],
|
||||
retval['biBitCount']) = v
|
||||
v = struct.unpack('IIIII', t[20:40])
|
||||
(retval['biSizeImage'],
|
||||
retval['biXPelsPerMeter'],
|
||||
retval['biYPelsPerMeter'],
|
||||
retval['biClrUsed'],
|
||||
retval['biClrImportant'] ) = v
|
||||
retval['biClrImportant']) = v
|
||||
vi = core.VideoStream()
|
||||
vi.codec = t[16:20]
|
||||
vi.width = retval['biWidth']
|
||||
@@ -233,15 +231,15 @@ class Riff(core.AVContainer):
|
||||
return retval
|
||||
|
||||
|
||||
def _parseSTRL(self,t):
|
||||
def _parseSTRL(self, t):
|
||||
retval = {}
|
||||
size = len(t)
|
||||
i = 0
|
||||
|
||||
while i < len(t) - 8:
|
||||
key = t[i:i+4]
|
||||
sz = struct.unpack('<I',t[i+4:i+8])[0]
|
||||
i+=8
|
||||
key = t[i:i + 4]
|
||||
sz = struct.unpack('<I', t[i + 4:i + 8])[0]
|
||||
i += 8
|
||||
value = t[i:]
|
||||
|
||||
if key == 'strh':
|
||||
@@ -249,40 +247,40 @@ class Riff(core.AVContainer):
|
||||
elif key == 'strf':
|
||||
retval[key] = self._parseSTRF(value, retval['strh'])
|
||||
else:
|
||||
log.debug("_parseSTRL: unsupported stream tag '%s'", key)
|
||||
log.debug(u'_parseSTRL: unsupported stream tag %r', key)
|
||||
|
||||
i += sz
|
||||
|
||||
return retval, i
|
||||
|
||||
|
||||
def _parseODML(self,t):
|
||||
def _parseODML(self, t):
|
||||
retval = {}
|
||||
size = len(t)
|
||||
i = 0
|
||||
key = t[i:i+4]
|
||||
sz = struct.unpack('<I',t[i+4:i+8])[0]
|
||||
key = t[i:i + 4]
|
||||
sz = struct.unpack('<I', t[i + 4:i + 8])[0]
|
||||
i += 8
|
||||
value = t[i:]
|
||||
if key != 'dmlh':
|
||||
log.debug("_parseODML: Error")
|
||||
log.debug(u'_parseODML: Error')
|
||||
|
||||
i += sz - 8
|
||||
return (retval, i)
|
||||
|
||||
|
||||
def _parseVPRP(self,t):
|
||||
def _parseVPRP(self, t):
|
||||
retval = {}
|
||||
v = struct.unpack('<IIIIIIIIII',t[:4*10])
|
||||
v = struct.unpack('<IIIIIIIIII', t[:4 * 10])
|
||||
|
||||
( retval['VideoFormat'],
|
||||
(retval['VideoFormat'],
|
||||
retval['VideoStandard'],
|
||||
retval['RefreshRate'],
|
||||
retval['HTotalIn'],
|
||||
retval['VTotalIn'],
|
||||
retval['FrameAspectRatio'],
|
||||
retval['wPixel'],
|
||||
retval['hPixel'] ) = v[1:-1]
|
||||
retval['hPixel']) = v[1:-1]
|
||||
|
||||
# I need an avi with more informations
|
||||
# enum {FORMAT_UNKNOWN, FORMAT_PAL_SQUARE, FORMAT_PAL_CCIR_601,
|
||||
@@ -309,7 +307,7 @@ class Riff(core.AVContainer):
|
||||
# If the VOL header doesn't appear within 5MB or 5 video chunks,
|
||||
# give up. The 5MB limit is not likely to apply except in
|
||||
# pathological cases.
|
||||
while i < min(1024*1024*5, size - 8) and n_dc < 5:
|
||||
while i < min(1024 * 1024 * 5, size - 8) and n_dc < 5:
|
||||
data = file.read(8)
|
||||
if ord(data[0]) == 0:
|
||||
# Eat leading nulls.
|
||||
@@ -317,7 +315,7 @@ class Riff(core.AVContainer):
|
||||
i += 1
|
||||
|
||||
key, sz = struct.unpack('<4sI', data)
|
||||
if key[2:] != 'dc' or sz > 1024*500:
|
||||
if key[2:] != 'dc' or sz > 1024 * 500:
|
||||
# This chunk is not video or is unusually big (> 500KB);
|
||||
# skip it.
|
||||
file.seek(sz, 1)
|
||||
@@ -338,7 +336,7 @@ class Riff(core.AVContainer):
|
||||
startcode = 0xff
|
||||
def bits(v, o, n):
|
||||
# Returns n bits in v, offset o bits.
|
||||
return (v & 2**n-1 << (64-n-o)) >> 64-n-o
|
||||
return (v & 2 ** n - 1 << (64 - n - o)) >> 64 - n - o
|
||||
|
||||
while pos < sz:
|
||||
startcode = ((startcode << 8) | ord(data[pos])) & 0xffffffff
|
||||
@@ -350,7 +348,7 @@ class Riff(core.AVContainer):
|
||||
if startcode >= 0x120 and startcode <= 0x12F:
|
||||
# We have the VOL startcode. Pull 64 bits of it and treat
|
||||
# as a bitstream
|
||||
v = struct.unpack(">Q", data[pos : pos+8])[0]
|
||||
v = struct.unpack(">Q", data[pos : pos + 8])[0]
|
||||
offset = 10
|
||||
if bits(v, 9, 1):
|
||||
# is_ol_id, skip over vo_ver_id and vo_priority
|
||||
@@ -385,36 +383,36 @@ class Riff(core.AVContainer):
|
||||
|
||||
if i < size:
|
||||
# Seek past whatever might be remaining of the movi list.
|
||||
file.seek(size-i,1)
|
||||
file.seek(size - i, 1)
|
||||
|
||||
|
||||
|
||||
def _parseLIST(self,t):
|
||||
def _parseLIST(self, t):
|
||||
retval = {}
|
||||
i = 0
|
||||
size = len(t)
|
||||
|
||||
while i < size-8:
|
||||
while i < size - 8:
|
||||
# skip zero
|
||||
if ord(t[i]) == 0: i += 1
|
||||
key = t[i:i+4]
|
||||
key = t[i:i + 4]
|
||||
sz = 0
|
||||
|
||||
if key == 'LIST':
|
||||
sz = struct.unpack('<I',t[i+4:i+8])[0]
|
||||
i+=8
|
||||
key = "LIST:"+t[i:i+4]
|
||||
value = self._parseLIST(t[i:i+sz])
|
||||
sz = struct.unpack('<I', t[i + 4:i + 8])[0]
|
||||
i += 8
|
||||
key = "LIST:" + t[i:i + 4]
|
||||
value = self._parseLIST(t[i:i + sz])
|
||||
if key == 'strl':
|
||||
for k in value.keys():
|
||||
retval[k] = value[k]
|
||||
else:
|
||||
retval[key] = value
|
||||
i+=sz
|
||||
i += sz
|
||||
elif key == 'avih':
|
||||
sz = struct.unpack('<I',t[i+4:i+8])[0]
|
||||
sz = struct.unpack('<I', t[i + 4:i + 8])[0]
|
||||
i += 8
|
||||
value = self._parseAVIH(t[i:i+sz])
|
||||
value = self._parseAVIH(t[i:i + sz])
|
||||
i += sz
|
||||
retval[key] = value
|
||||
elif key == 'strl':
|
||||
@@ -433,15 +431,15 @@ class Riff(core.AVContainer):
|
||||
retval[key] = value
|
||||
i += sz
|
||||
elif key == 'JUNK':
|
||||
sz = struct.unpack('<I',t[i+4:i+8])[0]
|
||||
sz = struct.unpack('<I', t[i + 4:i + 8])[0]
|
||||
i += sz + 8
|
||||
else:
|
||||
sz = struct.unpack('<I',t[i+4:i+8])[0]
|
||||
i+=8
|
||||
sz = struct.unpack('<I', t[i + 4:i + 8])[0]
|
||||
i += 8
|
||||
# in most cases this is some info stuff
|
||||
if not key in AVIINFO.keys() and key != 'IDIT':
|
||||
log.debug("Unknown Key: %s, len: %d" % (key,sz))
|
||||
value = t[i:i+sz]
|
||||
log.debug(u'Unknown Key: %r, len: %d' % (key, sz))
|
||||
value = t[i:i + sz]
|
||||
if key == 'ISFT':
|
||||
# product information
|
||||
if value.find('\0') > 0:
|
||||
@@ -466,17 +464,17 @@ class Riff(core.AVContainer):
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
log.debug('no support for time format %s', value)
|
||||
i+=sz
|
||||
log.debug(u'no support for time format %r', value)
|
||||
i += sz
|
||||
return retval
|
||||
|
||||
|
||||
def _parseRIFFChunk(self,file):
|
||||
def _parseRIFFChunk(self, file):
|
||||
h = file.read(8)
|
||||
if len(h) < 8:
|
||||
return False
|
||||
name = h[:4]
|
||||
size = struct.unpack('<I',h[4:8])[0]
|
||||
size = struct.unpack('<I', h[4:8])[0]
|
||||
|
||||
if name == 'LIST':
|
||||
pos = file.tell() - 8
|
||||
@@ -488,18 +486,18 @@ class Riff(core.AVContainer):
|
||||
# header), but we do know the video's dimensions, and
|
||||
# we're dealing with an mpeg4 stream, try to get the aspect
|
||||
# from the VOL header in the mpeg4 stream.
|
||||
self._parseLISTmovi(size-4, file)
|
||||
self._parseLISTmovi(size - 4, file)
|
||||
return True
|
||||
elif size > 80000:
|
||||
log.debug('RIFF LIST "%s" too long to parse: %s bytes' % (key, size))
|
||||
t = file.seek(size-4,1)
|
||||
log.debug(u'RIFF LIST %r too long to parse: %r bytes' % (key, size))
|
||||
t = file.seek(size - 4, 1)
|
||||
return True
|
||||
elif size < 5:
|
||||
log.debug('RIFF LIST "%s" too short: %s bytes' % (key, size))
|
||||
log.debug(u'RIFF LIST %r too short: %r bytes' % (key, size))
|
||||
return True
|
||||
|
||||
t = file.read(size-4)
|
||||
log.debug('parse RIFF LIST "%s": %d bytes' % (key, size))
|
||||
t = file.read(size - 4)
|
||||
log.debug(u'parse RIFF LIST %r: %d bytes' % (key, size))
|
||||
value = self._parseLIST(t)
|
||||
self.header[key] = value
|
||||
if key == 'INFO':
|
||||
@@ -511,7 +509,7 @@ class Riff(core.AVContainer):
|
||||
# no need to add this info to a table
|
||||
pass
|
||||
else:
|
||||
log.debug('Skipping table info %s' % key)
|
||||
log.debug(u'Skipping table info %r' % key)
|
||||
|
||||
elif name == 'JUNK':
|
||||
self.junkStart = file.tell() - 8
|
||||
@@ -519,15 +517,15 @@ class Riff(core.AVContainer):
|
||||
file.seek(size, 1)
|
||||
elif name == 'idx1':
|
||||
self.has_idx = True
|
||||
log.debug('idx1: %s bytes' % size)
|
||||
log.debug(u'idx1: %r bytes' % size)
|
||||
# no need to parse this
|
||||
t = file.seek(size,1)
|
||||
t = file.seek(size, 1)
|
||||
elif name == 'RIFF':
|
||||
log.debug("New RIFF chunk, extended avi [%i]" % size)
|
||||
log.debug(u'New RIFF chunk, extended avi [%i]' % size)
|
||||
type = file.read(4)
|
||||
if type != 'AVIX':
|
||||
log.debug("Second RIFF chunk is %s, not AVIX, skipping", type)
|
||||
file.seek(size-4, 1)
|
||||
log.debug(u'Second RIFF chunk is %r, not AVIX, skipping', type)
|
||||
file.seek(size - 4, 1)
|
||||
# that's it, no new informations should be in AVIX
|
||||
return False
|
||||
elif name == 'fmt ' and size <= 50:
|
||||
@@ -556,11 +554,11 @@ class Riff(core.AVContainer):
|
||||
elif not name.strip(string.printable + string.whitespace):
|
||||
# check if name is something usefull at all, maybe it is no
|
||||
# avi or broken
|
||||
t = file.seek(size,1)
|
||||
log.debug("Skipping %s [%i]" % (name,size))
|
||||
t = file.seek(size, 1)
|
||||
log.debug(u'Skipping %r [%i]' % (name, size))
|
||||
else:
|
||||
# bad avi
|
||||
log.debug("Bad or broken avi")
|
||||
log.debug(u'Bad or broken avi')
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# enzyme - Video metadata parser
|
||||
# Copyright (C) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright (C) 2006-2009 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright (C) 2006-2009 Jason Tackaberry
|
||||
# Copyright 2011-2012 Antoine Bertin <diaoulael@gmail.com>
|
||||
# Copyright 2006-2009 Dirk Meyer <dischi@freevo.org>
|
||||
# Copyright 2006-2009 Jason Tackaberry
|
||||
#
|
||||
# This file is part of enzyme.
|
||||
#
|
||||
@@ -17,9 +17,7 @@
|
||||
# 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__ = ['ENCODING', 'str_to_unicode', 'unicode_to_str']
|
||||
|
||||
import locale
|
||||
|
||||
Reference in new issue
Block a user