More Dolby metadata support

This commit is contained in:
Jamie Hardt
2022-11-25 13:03:33 -08:00
parent cc49df8f08
commit ff60f26f78
4 changed files with 34 additions and 17 deletions

View File

@@ -33,7 +33,6 @@ class TestDolby(TestCase):
self.assertTrue(seg[1]) self.assertTrue(seg[1])
def test_ddp(self): def test_ddp(self):
t1 = wavinfo.WavInfoReader(self.test_file) t1 = wavinfo.WavInfoReader(self.test_file)
d = t1.dolby d = t1.dolby
@@ -42,7 +41,6 @@ class TestDolby(TestCase):
self.assertTrue( ddp[0].audio_coding_mode, DolbyDigitalPlusMetadata.AudioCodingMode.CH_ORD_3_2 ) self.assertTrue( ddp[0].audio_coding_mode, DolbyDigitalPlusMetadata.AudioCodingMode.CH_ORD_3_2 )
self.assertTrue( ddp[0].lfe_on) self.assertTrue( ddp[0].lfe_on)
def test_atmos(self): def test_atmos(self):
t1 = wavinfo.WavInfoReader(self.test_file) t1 = wavinfo.WavInfoReader(self.test_file)
d = t1.dolby d = t1.dolby

View File

@@ -3,7 +3,14 @@ import datetime
from . import WavInfoReader from . import WavInfoReader
import sys import sys
import json import json
from enum import Enum
class MyJSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Enum):
return dict(name=o._name_, value=o._value_)
else:
return super().default(o)
def main(): def main():
parser = OptionParser() parser = OptionParser()
@@ -25,7 +32,7 @@ def main():
ret_dict['scopes'][scope][name] = value ret_dict['scopes'][scope][name] = value
json.dump(ret_dict, fp=sys.stdout, indent=2) json.dump(ret_dict, cls=MyJSONEncoder, fp=sys.stdout, indent=2)
except Exception as e: except Exception as e:
print(e) print(e)

View File

@@ -9,7 +9,7 @@ Unless otherwise stated, all § references here are to
from enum import IntEnum, Enum from enum import IntEnum, Enum
from struct import unpack from struct import unpack
from dataclasses import dataclass from dataclasses import dataclass, asdict
from typing import List, Optional, Tuple, Any, Union from typing import List, Optional, Tuple, Any, Union
from io import BytesIO from io import BytesIO
@@ -255,10 +255,6 @@ class DolbyDigitalPlusMetadata:
RESERVED = 3 RESERVED = 3
class DataRate(int):
pass
class RFCompressionProfile(Enum): class RFCompressionProfile(Enum):
""" """
`compr1` RF compression profile `compr1` RF compression profile
@@ -419,7 +415,7 @@ class DolbyDigitalPlusMetadata:
pass pass
def datarate(b) -> int: def datarate(b) -> int:
return b return unpack("<H", b)[0]
def reserved(_): def reserved(_):
pass pass
@@ -436,13 +432,13 @@ class DolbyDigitalPlusMetadata:
downmix_mode, ltrt_center_downmix_level, ltrt_surround_downmix_level = ext_bsi1_word2(buffer[9]) downmix_mode, ltrt_center_downmix_level, ltrt_surround_downmix_level = ext_bsi1_word2(buffer[9])
surround_ex_mode, dolby_headphone_encoded, ad_converter_type = ext_bsi2_word1(buffer[10]) surround_ex_mode, dolby_headphone_encoded, ad_converter_type = ext_bsi2_word1(buffer[10])
ddplus_reserved2(buffer[11:3]) ddplus_reserved2(buffer[11:14])
compression = compr1(buffer[14]) compression = compr1(buffer[14])
dynamic_range = dynrng1(buffer[15]) dynamic_range = dynrng1(buffer[15])
ddplus_reserved3(buffer[16:3]) ddplus_reserved3(buffer[16:19])
stream_info = ddplus_info1(buffer[19]) stream_info = ddplus_info1(buffer[19])
ddplus_reserved4(buffer[20:5]) ddplus_reserved4(buffer[20:25])
data_rate = datarate(buffer[25:2]) data_rate = datarate(buffer[25:27])
reserved(buffer[27:69]) reserved(buffer[27:69])
return DolbyDigitalPlusMetadata(program_id=pid, return DolbyDigitalPlusMetadata(program_id=pid,
@@ -481,7 +477,7 @@ class DolbyAtmosMetadata:
https://github.com/DolbyLaboratories/dbmd-atmos-parser/ https://github.com/DolbyLaboratories/dbmd-atmos-parser/
""" """
class WarpMode(IntEnum): class WarpMode(Enum):
NORMAL = 0x00 NORMAL = 0x00
WARPING = 0x01 WARPING = 0x01
DOWNMIX_PLIIX = 0x02 DOWNMIX_PLIIX = 0x02
@@ -538,6 +534,10 @@ class DolbyAtmosSupplementalMetadata:
render_modes: List['DolbyAtmosMetadata.BinauralRenderMode'] render_modes: List['DolbyAtmosMetadata.BinauralRenderMode']
trim_modes: List[int] trim_modes: List[int]
@classmethod
def load(cls, data: bytes):
pass
class WavDolbyMetadataReader: class WavDolbyMetadataReader:
@@ -594,6 +594,8 @@ class WavDolbyMetadataReader:
segment = DolbyDigitalPlusMetadata.load(segment) segment = DolbyDigitalPlusMetadata.load(segment)
elif stype == SegmentType.DolbyAtmos: elif stype == SegmentType.DolbyAtmos:
segment = DolbyAtmosMetadata.load(segment) segment = DolbyAtmosMetadata.load(segment)
elif stype == SegmentType.DolbyAtmosSupplemental:
segment = DolbyAtmosSupplementalMetadata.load(segment)
self.segment_list.append( (stype, checksum == expected_checksum, segment) ) self.segment_list.append( (stype, checksum == expected_checksum, segment) )
@@ -617,3 +619,13 @@ class WavDolbyMetadataReader:
""" """
return [x[2] for x in self.segment_list \ return [x[2] for x in self.segment_list \
if x[0] == SegmentType.DolbyAtmosSupplemental and x[1]] if x[0] == SegmentType.DolbyAtmosSupplemental and x[1]]
def to_dict(self) -> dict:
ddp = map(lambda x: asdict(x), self.dolby_digital_plus())
atmos = map(lambda x: asdict(x), self.dolby_atmos())
atmos_sup = [] #map(lambda x: asdict(x), self.dolby_atmos_supplemental())
return dict(dolby_digital_plus=list(ddp),
dolby_atmos=list(atmos),
dolby_atmos_supplemental=list(atmos_sup))

View File

@@ -169,10 +169,10 @@ class WavInfoReader:
:yields: tuples of the *scope*, *key*, and *value* of :yields: tuples of the *scope*, *key*, and *value* of
each metadatum. The *scope* value will be one of each metadatum. The *scope* value will be one of
"fmt", "data", "ixml", "bext", "info" or "adm". "fmt", "data", "ixml", "bext", "info", "dolby", or "adm".
""" """
scopes = ('fmt', 'data', 'ixml', 'bext', 'info', 'adm') scopes = ('fmt', 'data', 'ixml', 'bext', 'info', 'adm', 'dolby')
for scope in scopes: for scope in scopes:
if scope in ['fmt', 'data']: if scope in ['fmt', 'data']: