Skip to content

Commit

Permalink
Add the properties bitrate_mode, encoder_info and encoder_settings
Browse files Browse the repository at this point in the history
  • Loading branch information
jcassette committed Nov 22, 2021
1 parent 055c490 commit 7509a4b
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 2 deletions.
7 changes: 6 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The metadata schema is generally based on MusicBrainz' schema with similar namin
* ``lyrics``, ``copyright``, ``url``
* calculated metadata like ``bpm`` (beats per minute) and ``r128_track_gain`` (ReplayGain),
* embedded images (e.g. album art),
* file metadata like ``bitrate`` and ``length``.
* file metadata like ``samplerate``, ``bitdepth``, ``channels``, ``bitrate``, ``bitrate_mode``, ``encoder_info``, ``encoder_settings`` and ``length``.

Compatibility
-------------
Expand Down Expand Up @@ -135,6 +135,11 @@ To copy tags from one MediaFile to another:
Changelog
---------
v0.8.2
''''''
- Add the properties ``bitrate_mode``, ``encoder_info`` and ``encoder_settings``.
v0.8.1
''''''
Expand Down
40 changes: 39 additions & 1 deletion mediafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

import mutagen
import mutagen.id3
import mutagen.mp3
import mutagen.mp4
import mutagen.flac
import mutagen.asf
Expand Down Expand Up @@ -1721,7 +1722,8 @@ def readable_fields(cls):
for property in cls.fields():
yield property
for property in ('length', 'samplerate', 'bitdepth', 'bitrate',
'channels', 'format'):
'bitrate_mode', 'channels', 'encoder_info',
'encoder_settings', 'format'):
yield property

@classmethod
Expand Down Expand Up @@ -2326,6 +2328,42 @@ def bitrate(self):
return 0
return int(self.filesize * 8 / self.length)

@property
def bitrate_mode(self):
"""The mode of the bitrate used in the audio coding
(a string, eg. "CBR", "VBR" or "ABR").
Only available for the MP3 file format (empty where unavailable).
"""
if hasattr(self.mgfile.info, 'bitrate_mode'):
return {
mutagen.mp3.BitrateMode.CBR: 'CBR',
mutagen.mp3.BitrateMode.VBR: 'VBR',
mutagen.mp3.BitrateMode.ABR: 'ABR',
}.get(self.mgfile.info.bitrate_mode, '')
else:
return ''

@property
def encoder_info(self):
"""The name and/or version of the encoder used
(a string, eg. "LAME 3.97.0").
Only available for some formats (empty where unavailable).
"""
if hasattr(self.mgfile.info, 'encoder_info'):
return self.mgfile.info.encoder_info
else:
return ''

@property
def encoder_settings(self):
"""A guess of the settings used for the encoder (a string, eg. "-V2").
Only available for the MP3 file format (empty where unavailable).
"""
if hasattr(self.mgfile.info, 'encoder_settings'):
return self.mgfile.info.encoder_settings
else:
return ''

@property
def format(self):
"""A string describing the file format/codec."""
Expand Down
Binary file added test/rsrc/cbr.mp3
Binary file not shown.
51 changes: 51 additions & 0 deletions test/test_mediafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,9 @@ class MP3Test(ReadWriteTestBase, PartialTestMixin,
audio_properties = {
'length': 1.0,
'bitrate': 80000,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': 'MP3',
'samplerate': 44100,
'bitdepth': 0,
Expand All @@ -771,13 +774,28 @@ def test_unknown_apic_type(self):
mediafile = self._mediafile_fixture('image_unknown_type')
self.assertEqual(mediafile.images[0].type, ImageType.other)

def test_bitrate_mode(self):
mediafile = self._mediafile_fixture('cbr')
self.assertEqual(mediafile.bitrate_mode, 'CBR')

def test_encoder_info(self):
mediafile = self._mediafile_fixture('cbr')
self.assertEqual(mediafile.encoder_info, 'LAME 3.100.0+')

def test_encoder_settings(self):
mediafile = self._mediafile_fixture('cbr')
self.assertEqual(mediafile.encoder_settings, '-b 80')


class MP4Test(ReadWriteTestBase, PartialTestMixin,
ImageStructureTestMixin, unittest.TestCase):
extension = 'm4a'
audio_properties = {
'length': 1.0,
'bitrate': 64000,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': 'AAC',
'samplerate': 44100,
'bitdepth': 16,
Expand All @@ -799,6 +817,9 @@ class AlacTest(ReadWriteTestBase, unittest.TestCase):
audio_properties = {
'length': 1.0,
'bitrate': 21830,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
# 'format': 'ALAC',
'samplerate': 44100,
'bitdepth': 16,
Expand All @@ -811,6 +832,9 @@ class MusepackTest(ReadWriteTestBase, unittest.TestCase):
audio_properties = {
'length': 1.0,
'bitrate': 24023,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'Musepack',
'samplerate': 44100,
'bitdepth': 0,
Expand All @@ -824,6 +848,9 @@ class WMATest(ReadWriteTestBase, ExtendedImageStructureTestMixin,
audio_properties = {
'length': 1.0,
'bitrate': 128000,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'Windows Media',
'samplerate': 44100,
'bitdepth': 0,
Expand Down Expand Up @@ -852,6 +879,9 @@ class OggTest(ReadWriteTestBase, ExtendedImageStructureTestMixin,
audio_properties = {
'length': 1.0,
'bitrate': 48000,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'OGG',
'samplerate': 44100,
'bitdepth': 0,
Expand Down Expand Up @@ -896,6 +926,9 @@ class FlacTest(ReadWriteTestBase, PartialTestMixin,
audio_properties = {
'length': 1.0,
'bitrate': 108688,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'FLAC',
'samplerate': 44100,
'bitdepth': 16,
Expand All @@ -909,6 +942,9 @@ class ApeTest(ReadWriteTestBase, ExtendedImageStructureTestMixin,
audio_properties = {
'length': 1.0,
'bitrate': 112608,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'APE',
'samplerate': 44100,
'bitdepth': 16,
Expand All @@ -921,6 +957,9 @@ class WavpackTest(ReadWriteTestBase, unittest.TestCase):
audio_properties = {
'length': 1.0,
'bitrate': 109312,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'WavPack',
'samplerate': 44100,
'bitdepth': 16 if mutagen.version >= (1, 45, 0) else 0,
Expand All @@ -933,6 +972,9 @@ class OpusTest(ReadWriteTestBase, unittest.TestCase):
audio_properties = {
'length': 1.0,
'bitrate': 66792,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'Opus',
'samplerate': 48000,
'bitdepth': 0,
Expand All @@ -945,6 +987,9 @@ class AIFFTest(ReadWriteTestBase, unittest.TestCase):
audio_properties = {
'length': 1.0,
'bitrate': 705600,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'AIFF',
'samplerate': 44100,
'bitdepth': 16,
Expand All @@ -957,6 +1002,9 @@ class WAVETest(ReadWriteTestBase, unittest.TestCase):
audio_properties = {
'length': 1.0,
'bitrate': 88200,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'WAVE',
'samplerate': 44100,
'bitdepth': 16,
Expand Down Expand Up @@ -1033,6 +1081,9 @@ class DSFTest(ReadWriteTestBase, unittest.TestCase):
audio_properties = {
'length': 0.01,
'bitrate': 11289600,
'bitrate_mode': '',
'encoder_info': '',
'encoder_settings': '',
'format': u'DSD Stream File',
'samplerate': 5644800,
'bitdepth': 1,
Expand Down

0 comments on commit 7509a4b

Please sign in to comment.