Source code for pytomo.kaa_metadata.audio.ogg
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------------
# ogg.py - ogg file parser (vorbis only)
# -----------------------------------------------------------------------------
# $Id: ogg.py 3818 2009-01-27 16:52:21Z dmeyer $
#
# -----------------------------------------------------------------------------
# kaa-Metadata - Media Metadata for Python
# Copyright (C) 2003-2006 Thomas Schueppel, Dirk Meyer
#
# First Edition: Thomas Schueppel <stain@acm.org>
# Maintainer: Dirk Meyer <dischi@freevo.org>
#
# Please see the file AUTHORS for a complete list of authors.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------------
from __future__ import absolute_import
__all__ = ['Parser']
# python imports
import re
import os
import stat
import struct
import logging
# import kaa_metadata.audio core
from . import core
# get logging object
log = logging.getLogger('metadata')
VORBIS_PACKET_INFO = '\01vorbis'
VORBIS_PACKET_HEADER = '\03vorbis'
VORBIS_PACKET_SETUP = '\05vorbis'
class Ogg(core.Music):
def __init__(self,file):
core.Music.__init__(self)
h = file.read(4+1+1+20+1)
if h[:5] != "OggS\00":
log.info("Invalid header")
raise core.ParseError()
if ord(h[5]) != 2:
log.info("Invalid header type flag (trying to go ahead anyway)")
self.pageSegCount = ord(h[-1])
# Skip the PageSegCount
file.seek(self.pageSegCount,1)
h = file.read(7)
if h != VORBIS_PACKET_INFO:
log.info("Wrong vorbis header type, giving up.")
raise core.ParseError()
# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions
self.mime = 'audio/x-vorbis+ogg'
header = {}
info = file.read(23)
self.version, self.channels, self.samplerate, bitrate_max, \
self.bitrate, bitrate_min, blocksize, \
framing = struct.unpack('<IBIiiiBB',info[:23])
self.bitrate = self.bitrate / 1000
# INFO Header, read Oggs and skip 10 bytes
h = file.read(4+10+13)
if h[:4] == 'OggS':
(serial, pagesequence, checksum, numEntries) = \
struct.unpack( '<14xIIIB', h )
# skip past numEntries
file.seek(numEntries,1)
h = file.read(7)
if h != VORBIS_PACKET_HEADER:
# Not a corrent info header
return
self.encoder = self._extractHeaderString(file)
numItems = struct.unpack('<I',file.read(4))[0]
for i in range(numItems):
s = self._extractHeaderString(file)
a = re.split('=',s)
header[(a[0]).upper()]=a[1]
# Put Header fields into info fields
if header.has_key('TITLE'):
self.title = header['TITLE']
if header.has_key('ALBUM'):
self.album = header['ALBUM']
if header.has_key('ARTIST'):
self.artist = header['ARTIST']
if header.has_key('COMMENT'):
self.comment = header['COMMENT']
if header.has_key('DATE'):
# FIXME: try to convert to timestamp
self.userdate = header['DATE']
if header.has_key('ENCODER'):
self.encoder = header['ENCODER']
if header.has_key('TRACKNUMBER'):
self.trackno = header['TRACKNUMBER']
self.type = 'OGG Vorbis'
self.subtype = ''
self.length = self._calculateTrackLength(file)
self._appendtable('VORBISCOMMENT',header)
def _extractHeaderString(self,f):
len = struct.unpack( '<I', f.read(4) )[0]
return unicode(f.read(len), 'utf-8')
def _calculateTrackLength(self,f):
# seek to the end of the stream, to avoid scanning the whole file
if (os.stat(f.name)[stat.ST_SIZE] > 20000):
f.seek(os.stat(f.name)[stat.ST_SIZE]-10000)
# read the rest of the file into a buffer
h = f.read()
granule_position = 0
# search for each 'OggS' in h
if len(h):
idx = h.rfind('OggS')
if idx < 0:
return 0
pageSize = 0
h = h[idx+4:]
(check, type, granule_position, absPos, serial, pageN, crc, \
segs) = struct.unpack( '<BBIIIIIB', h[:23] )
if check != 0:
log.debug(h[:10])
return
log.debug("granule = %d / %d" % (granule_position, absPos))
# the last one is the one we are interested in
return float(granule_position) / self.samplerate
Parser = Ogg