mirror of
https://github.com/iluvcapra/wavinfo.git
synced 2025-12-31 08:50:41 +00:00
Dolby metadata integration
This commit is contained in:
@@ -12,10 +12,11 @@ from struct import unpack
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Tuple, Any
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
class SegmentType(IntEnum):
|
||||
"""
|
||||
|
||||
Metadata segment type.
|
||||
"""
|
||||
EndMarker = 0x0
|
||||
DolbyE = 0x1
|
||||
@@ -78,6 +79,9 @@ class DolbyDigitalPlusMetadata:
|
||||
|
||||
|
||||
class DolbySurroundEncodingMode(Enum):
|
||||
"""
|
||||
Dolby surround endcoding mode.
|
||||
"""
|
||||
RESERVED = 0b11
|
||||
IN_USE = 0b10
|
||||
NOT_IN_USE = 0b01
|
||||
@@ -169,13 +173,13 @@ class DolbyDigitalPlusMetadata:
|
||||
RESERVED = 0b11
|
||||
|
||||
|
||||
class LanguageCode(Enum):
|
||||
class LanguageCode(int):
|
||||
"""
|
||||
§ 4.3.4.1
|
||||
Per ATSC/A52 § 5.4.2.12 this is not in use and always 0xFF
|
||||
"""
|
||||
|
||||
NONE = 0xff
|
||||
Per ATSC/A52 § 5.4.2.12, this is not in use and always 0xFF.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class MixLevel(int):
|
||||
@@ -204,6 +208,8 @@ class DolbyDigitalPlusMetadata:
|
||||
|
||||
class PreferredDownMixMode(Enum):
|
||||
"""
|
||||
Indicates the creating engineer's preference of what the receiver should
|
||||
downmix.
|
||||
§ 4.3.8.1
|
||||
"""
|
||||
NOT_INDICATED = 0b00
|
||||
@@ -214,6 +220,7 @@ class DolbyDigitalPlusMetadata:
|
||||
|
||||
class SurroundEXMode(IntEnum):
|
||||
"""
|
||||
Dolby Surround-EX mode.
|
||||
`dsurexmod` § 4.3.9.1
|
||||
"""
|
||||
NOT_INDICATED = 0b00
|
||||
@@ -332,10 +339,15 @@ class DolbyDigitalPlusMetadata:
|
||||
|
||||
#: Dolby Headphone mode
|
||||
dolby_headphone_encoded: HeadphoneMode
|
||||
|
||||
ad_converter_type: ADConverterType
|
||||
compression_profile: RFCompressionProfile
|
||||
dynamic_range: RFCompressionProfile
|
||||
stream_type: StreamDependency
|
||||
|
||||
#: Indicates if this stream can be decoded independently or not
|
||||
stream_dependency: StreamDependency
|
||||
|
||||
#: Data rate of this bitstream in kilobits per second
|
||||
datarate_kbps: int
|
||||
|
||||
@staticmethod
|
||||
@@ -460,11 +472,11 @@ class DolbyDigitalPlusMetadata:
|
||||
ad_converter_type=ad_converter_type,
|
||||
compression_profile=compression,
|
||||
dynamic_range=dynamic_range,
|
||||
stream_type=stream_info,
|
||||
stream_dependency=stream_info,
|
||||
datarate_kbps=data_rate)
|
||||
|
||||
|
||||
class WavDolbyChunkReader:
|
||||
class WavDolbyMetadataReader:
|
||||
"""
|
||||
Reads Dolby bitstream metadata.
|
||||
"""
|
||||
@@ -477,8 +489,23 @@ class WavDolbyChunkReader:
|
||||
#: not recognized).
|
||||
segment_list: Tuple[SegmentType | int, bool, Any]
|
||||
|
||||
version: str
|
||||
|
||||
def __init__(self, dbmd_data) -> None:
|
||||
self.segment_list = []
|
||||
|
||||
h = BytesIO(dbmd_data)
|
||||
|
||||
v_vec = []
|
||||
for _ in range(4):
|
||||
b = h.read(1)
|
||||
v_vec.insert(0, str(unpack("B", b[0:1])))
|
||||
|
||||
self.version = ".".join(v_vec)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from .wave_ixml_reader import WavIXMLFormat
|
||||
from .wave_bext_reader import WavBextReader
|
||||
from .wave_info_reader import WavInfoChunkReader
|
||||
from .wave_adm_reader import WavADMReader
|
||||
from .wave_dbmd_reader import WavDolbyMetadataReader
|
||||
|
||||
#: Calculated statistics about the audio data.
|
||||
WavDataDescriptor = namedtuple('WavDataDescriptor', 'byte_count frame_count')
|
||||
@@ -63,20 +64,23 @@ class WavInfoReader:
|
||||
|
||||
self.path = absolute_path
|
||||
|
||||
#: Wave audio data format
|
||||
self.fmt :Optional[WavAudioFormat] = None
|
||||
":class:`wavinfo.wave_reader.WavAudioFormat`"
|
||||
|
||||
#: Broadcast-Wave metadata
|
||||
self.bext :Optional[WavBextReader] = None
|
||||
":class:`wavinfo.wave_bext_reader.WavBextReader` with Broadcast-WAV metadata"
|
||||
|
||||
#: iXML metadata
|
||||
self.ixml :Optional[WavIXMLFormat] = None
|
||||
":class:`wavinfo.wave_ixml_reader.WavIXMLFormat` with iXML metadata"
|
||||
|
||||
#: ADM Audio Definiton Model metadata
|
||||
self.adm :Optional[WavADMReader]= None
|
||||
":class:`wavinfo.wave_axml_reader.WavADMReader` with ADM metadata"
|
||||
|
||||
#: Dolby Bitstream Metadata
|
||||
self.dolby :Optional[WavDolbyMetadataReader] = None
|
||||
|
||||
#: RIFF INFO Metadata
|
||||
self.info :Optional[WavInfoChunkReader]= None
|
||||
":class:`wavinfo.wave_info_reader.WavInfoChunkReader` with RIFF INFO metadata"
|
||||
|
||||
with open(path, 'rb') as f:
|
||||
self.get_wav_info(f)
|
||||
@@ -92,6 +96,7 @@ class WavInfoReader:
|
||||
self.ixml = self._get_ixml(wavfile)
|
||||
self.adm = self._get_adm(wavfile)
|
||||
self.info = self._get_info(wavfile, encoding=self.info_encoding)
|
||||
self.dolby = self._get_dbmd(wavfile)
|
||||
self.data = self._describe_data()
|
||||
|
||||
def _find_chunk_data(self, ident, from_stream, default_none=False):
|
||||
@@ -150,9 +155,13 @@ class WavInfoReader:
|
||||
chna = self._find_chunk_data(b'chna', f, default_none=True)
|
||||
return WavADMReader(axml_data=axml, chna_data=chna) if axml and chna else None
|
||||
|
||||
def _get_dbmd(self, f):
|
||||
dbmd_data = self._find_chunk_data(b'dbmd', f, default_none=True)
|
||||
return WavDolbyMetadataReader(dbmd_data=dbmd_data) if dbmd_data else None
|
||||
|
||||
def _get_ixml(self, f):
|
||||
ixml_data = self._find_chunk_data(b'iXML', f, default_none=True)
|
||||
return None if ixml_data is None else WavIXMLFormat(ixml_data.rstrip(b'\0'))
|
||||
return WavIXMLFormat(ixml_data.rstrip(b'\0')) if ixml_data else None
|
||||
|
||||
def walk(self) -> Generator[str,str,Any]:
|
||||
"""
|
||||
@@ -176,6 +185,5 @@ class WavInfoReader:
|
||||
for key in dict.keys():
|
||||
yield scope, key, dict[key]
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return 'WavInfoReader({}, {}, {})'.format(self.path, self.info_encoding, self.bext_encoding)
|
||||
|
||||
Reference in New Issue
Block a user