mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-01 00:43:37 +00:00
980e05cc99
Backported 400 revisions from rev 1de4961-8897c5b (2018-2014). Move core/benchmark, core/cmd_line, core/memory, core/profiler and core/timeout to core/optional/* Remove metadata/qt* PORT: Version 2.0a3 (inline with 3.0a3 @ f80c7d5). Basic Support for XMP Packets. tga: improvements to adhere more closely to the spec. pdf: slightly improved parsing. rar: fix TypeError on unknown block types. Add MacRoman win32 codepage. tiff/exif: support SubIFDs and tiled images. Add method to export metadata in dictionary. mpeg_video: don't attempt to parse Stream past length. mpeg_video: parse ESCR correctly, add SCR value. Change centralise CustomFragments. field: don't set parser class if class is None, to enable autodetect. field: add value/display for CustomFragment. parser: inline warning to enable tracebacks in debug mode. Fix empty bytestrings in makePrintable. Fix contentSize in jpeg.py to account for image_data blocks. Fix the ELF parser. Enhance the AR archive parser. elf parser: fix wrong wrong fields order in parsing little endian section flags. elf parser: add s390 as a machine type. Flesh out mp4 parser. PORT: Version 2.0a1 (inline with 3.0a1). Major refactoring and PEP8. Fix ResourceWarning warnings on files. Add a close() method and support for the context manager protocol ("with obj: ...") to parsers, input and output streams. metadata: get comment from ZIP. Support for InputIOStream.read(0). Fix sizeGe when size is None. Remove unused new_seekable_field_set file. Remove parser Mapsforge .map. Remove parser Parallel Realities Starfighter .pak files. sevenzip: fix for newer archives. java: update access flags and modifiers for Java 1.7 and update description text for most recent Java. Support ustar prefix field in tar archives. Remove file_system* parsers. Remove misc parsers 3d0, 3ds, gnome_keyring, msoffice*, mstask, ole*, word*. Remove program parsers macho, nds, prc. Support non-8bit Character subclasses. Python parser supports Python 3.7. Enhance mpeg_ts parser to support MTS/M2TS. Support for creation date in tiff. Change don't hardcode errno constant. PORT: 1.9.1 Internal Only: The following are legacy reference to upstream commit messages. Relevant changes up to b0a115f8. Use integer division. Replace HACHOIR_ERRORS with Exception. Fix metadata.Data: make it sortable. Import fixes from e7de492. PORT: Version 2.0a1 (inline with 3.0a1 @ e9f8fad). Replace hachoir.core.field with hachoir.field Replace hachoir.core.stream with hachoir.stream Remove the compatibility module for PY1.5 to PY2.5. metadata: support TIFF picture. metadata: fix string normalization. metadata: fix datetime regex Fix hachoir bug #57. FileFromInputStream: fix comparison between None and an int. InputIOStream: open the file in binary mode.
166 lines
5.5 KiB
Python
166 lines
5.5 KiB
Python
"""
|
|
FLAC (audio) parser
|
|
|
|
Documentation:
|
|
|
|
* http://flac.sourceforge.net/format.html
|
|
|
|
Author: Esteban Loiseau <baal AT tuxfamily.org>
|
|
Creation date: 2008-04-09
|
|
"""
|
|
|
|
from hachoir.parser import Parser
|
|
from hachoir.field import FieldSet, String, Bit, Bits, UInt16, UInt24, RawBytes, Enum, NullBytes
|
|
from hachoir.stream import BIG_ENDIAN, LITTLE_ENDIAN
|
|
from hachoir.core.tools import createDict
|
|
from hachoir.parser.container.ogg import parseVorbisComment
|
|
|
|
|
|
class VorbisComment(FieldSet):
|
|
endian = LITTLE_ENDIAN
|
|
createFields = parseVorbisComment
|
|
|
|
|
|
class StreamInfo(FieldSet):
|
|
static_size = 34 * 8
|
|
|
|
def createFields(self):
|
|
yield UInt16(self, "min_block_size", "The minimum block size (in samples) used in the stream")
|
|
yield UInt16(self, "max_block_size", "The maximum block size (in samples) used in the stream")
|
|
yield UInt24(self, "min_frame_size", "The minimum frame size (in bytes) used in the stream")
|
|
yield UInt24(self, "max_frame_size", "The maximum frame size (in bytes) used in the stream")
|
|
yield Bits(self, "sample_hertz", 20, "Sample rate in Hertz")
|
|
yield Bits(self, "nb_channel", 3, "Number of channels minus one")
|
|
yield Bits(self, "bits_per_sample", 5, "Bits per sample minus one")
|
|
yield Bits(self, "total_samples", 36, "Total samples in stream")
|
|
yield RawBytes(self, "md5sum", 16, "MD5 signature of the unencoded audio data")
|
|
|
|
|
|
class SeekPoint(FieldSet):
|
|
def createFields(self):
|
|
yield Bits(self, "sample_number", 64, "Sample number")
|
|
yield Bits(self, "offset", 64, "Offset in bytes")
|
|
yield Bits(self, "nb_sample", 16)
|
|
|
|
|
|
class SeekTable(FieldSet):
|
|
def createFields(self):
|
|
while not self.eof:
|
|
yield SeekPoint(self, "point[]")
|
|
|
|
|
|
class MetadataBlock(FieldSet):
|
|
"Metadata block field: http://flac.sourceforge.net/format.html#metadata_block"
|
|
|
|
BLOCK_TYPES = {
|
|
0: ("stream_info", u"Stream info", StreamInfo),
|
|
1: ("padding[]", u"Padding", None),
|
|
2: ("application[]", u"Application", None),
|
|
3: ("seek_table", u"Seek table", SeekTable),
|
|
4: ("comment", u"Vorbis comment", VorbisComment),
|
|
5: ("cue_sheet[]", u"Cue sheet", None),
|
|
6: ("picture[]", u"Picture", None),
|
|
}
|
|
BLOCK_TYPE_DESC = createDict(BLOCK_TYPES, 1)
|
|
|
|
def __init__(self, *args, **kw):
|
|
FieldSet.__init__(self, *args, **kw)
|
|
self._size = 32 + self["metadata_length"].value * 8
|
|
try:
|
|
key = self["block_type"].value
|
|
self._name, self._description, self.handler = self.BLOCK_TYPES[key]
|
|
except KeyError:
|
|
self.handler = None
|
|
|
|
def createFields(self):
|
|
yield Bit(self, "last_metadata_block", "True if this is the last metadata block")
|
|
yield Enum(Bits(self, "block_type", 7, "Metadata block header type"), self.BLOCK_TYPE_DESC)
|
|
yield UInt24(self, "metadata_length", "Length of following metadata in bytes (doesn't include this header)")
|
|
|
|
block_type = self["block_type"].value
|
|
size = self["metadata_length"].value
|
|
if not size:
|
|
return
|
|
try:
|
|
handler = self.BLOCK_TYPES[block_type][2]
|
|
except KeyError:
|
|
handler = None
|
|
if handler:
|
|
yield handler(self, "content", size=size * 8)
|
|
elif self["block_type"].value == 1:
|
|
yield NullBytes(self, "padding", size)
|
|
else:
|
|
yield RawBytes(self, "rawdata", size)
|
|
|
|
|
|
class Metadata(FieldSet):
|
|
def createFields(self):
|
|
while not self.eof:
|
|
field = MetadataBlock(self, "metadata_block[]")
|
|
yield field
|
|
if field["last_metadata_block"].value:
|
|
break
|
|
|
|
|
|
class Frame(FieldSet):
|
|
SAMPLE_RATES = {
|
|
0: "get from STREAMINFO metadata block",
|
|
1: "88.2kHz",
|
|
2: "176.4kHz",
|
|
3: "192kHz",
|
|
4: "8kHz",
|
|
5: "16kHz",
|
|
6: "22.05kHz",
|
|
7: "24kHz",
|
|
8: "32kHz",
|
|
9: "44.1kHz",
|
|
10: "48kHz",
|
|
11: "96kHz",
|
|
12: "get 8 bit sample rate (in kHz) from end of header",
|
|
13: "get 16 bit sample rate (in Hz) from end of header",
|
|
14: "get 16 bit sample rate (in tens of Hz) from end of header",
|
|
}
|
|
|
|
def createFields(self):
|
|
yield Bits(self, "sync", 14, "Sync code: 11111111111110")
|
|
yield Bit(self, "reserved[]")
|
|
yield Bit(self, "blocking_strategy")
|
|
yield Bits(self, "block_size", 4)
|
|
yield Enum(Bits(self, "sample_rate", 4), self.SAMPLE_RATES)
|
|
yield Bits(self, "channel_assign", 4)
|
|
yield Bits(self, "sample_size", 3)
|
|
yield Bit(self, "reserved[]")
|
|
# FIXME: Finish frame header parser
|
|
|
|
|
|
class Frames(FieldSet):
|
|
def createFields(self):
|
|
while not self.eof:
|
|
yield Frame(self, "frame[]")
|
|
# FIXME: Parse all frames
|
|
return
|
|
|
|
|
|
class FlacParser(Parser):
|
|
"Parse FLAC audio files: FLAC is a lossless audio codec"
|
|
MAGIC = "fLaC\x00"
|
|
PARSER_TAGS = {
|
|
"id": "flac",
|
|
"category": "audio",
|
|
"file_ext": ("flac",),
|
|
"mime": (u"audio/x-flac",),
|
|
"magic": ((MAGIC, 0),),
|
|
"min_size": 4 * 8,
|
|
"description": "FLAC audio",
|
|
}
|
|
endian = BIG_ENDIAN
|
|
|
|
def validate(self):
|
|
if self.stream.readBytes(0, len(self.MAGIC)) != self.MAGIC:
|
|
return u"Invalid magic string"
|
|
return True
|
|
|
|
def createFields(self):
|
|
yield String(self, "signature", 4, charset="ASCII", description="FLAC signature: fLaC string")
|
|
yield Metadata(self, "metadata")
|
|
yield Frames(self, "frames")
|