Skip to content

Commit

Permalink
Add ability to configure audio encoding
Browse files Browse the repository at this point in the history
Still can't do pass-through though...

Fixes: #5
  • Loading branch information
waveform80 committed Jul 27, 2024
1 parent 0033659 commit 3c8156e
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ application).
var_api_url
var_atomicparsley
var_audio_all
var_audio_encoding
var_audio_langs
var_audio_mix
var_decomb
Expand Down
75 changes: 75 additions & 0 deletions docs/var_audio_encoding.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.. tvrip: extract and transcode DVDs of TV series
..
.. Copyright (c) 2024 Dave Jones <dave@waveform.org.uk>
..
.. SPDX-License-Identifier: GPL-3.0-or-later
==============
audio_encoding
==============

::

set audio_encoding <encoding>

This setting specifies the encoder used for audio tracks on the ripped titles.
The valid values are:

``av_aac``
The default AAC encoder included with libav. This generally produces good
results in most cases at bitrates over 160kbps, but can struggle with
particular types of noise (wind noise in certain scenes has been known to
cause issues)

``fdk_aac``
The Fraunhofer AAC encoder. This generally produces good results at
bitrates over 160kbps.

.. warning::

Most builds of HandBrake do *not* include this codec as it is still
under patent in many jurisdictions.

``fdk_haac``
The Fraunhofer HE-AAC encoder. This produces good results in most cases at
bitrates over 96kbps. Be aware that many players do not support HE-AAC
decoding.

``mp3``
The LAME MP3 encoder. This produces good results at bitrates over 192kbps.
Be aware that some players will not support MP4 sources containing MP3
audio streams (such players tend to support AAC audio within MP4 only).

``vorbis``
Xiph's Vorbis encoder. This produces good results at bitrates over
160kbps. Be aware that, despite being an open format, support for Vorbis
decoding in players is relatively poor.

``opus``
Xiph's Opus encoder (the successor to the Vorbis format). This produces
good results at bitrates over 96kbps. Be aware that, despite being an open
format, support for Opus decoding in players is relatively poor.

``flac16`` or ``flac24``
Xiph's FLAC encoder. As a lossless format, this guarantees no degradation
in audio, but the compression is nowhere near that achieved by the lossy
codecs (typical bitrate is between 800 and 1400kbps). The number on the
end determines whether 16-bit or 24-bit samples are used.

.. note::

There is almost never a point to using ``flac24`` in ripping DVDs as
they use 16-bit audio samples. There *may* be a use for ``flac24``
when ripping Blu-ray, but you'd need to query the source to discover if
it's actually using more than 16-bit audio samples.

``ac3`` or ``eac3``
Dolby's AC-3 and E-AC-3 encodings. AC-3 is the native encoding used on DVD
discs, and produces very good quality, but as a rather old encoding it has
a rather high bitrate due to poor (by modern standards) compression. It is
common to find bitrates of 384kbps or greater on DVDs.


.. note::

Audio pass-through is not currently supported in tvrip.
20 changes: 19 additions & 1 deletion tests/test_ripcmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ def test_do_config(db, with_program, ripcmd, reader, tmp_path):
│ decomb │ auto
│ audio_mix │ dpl2
│ audio_all │ off
│ audio_encoding │ av_aac
│ audio_langs │ eng
│ subtitle_format │ none
│ subtitle_all │ off
Expand All @@ -594,7 +595,8 @@ def test_do_set(ripcmd):
def test_complete_set(ripcmd):
assert completions(ripcmd, 'set foo') == []
assert completions(ripcmd, 'set dvd') == ['dvdnav']
assert set(completions(ripcmd, 'set audio')) == {'audio_mix', 'audio_all', 'audio_langs'}
assert set(completions(ripcmd, 'set audio')) == {
'audio_mix', 'audio_all', 'audio_langs', 'audio_encoding'}
assert completions(ripcmd, 'set foo bar') is None
assert completions(ripcmd, 'set template foo') is None

Expand Down Expand Up @@ -837,6 +839,22 @@ def test_complete_set_audio_mix(db, with_config, ripcmd):
assert set(completions(ripcmd, 'set audio_mix s')) == {'stereo', 'surround'}


def test_set_audio_encoding(db, with_config, ripcmd):
with db.transaction():
assert ripcmd.config.audio_encoding == 'av_aac'
ripcmd.do_set('audio_encoding mp3')
assert ripcmd.config.audio_encoding == 'mp3'
with pytest.raises(CmdError):
ripcmd.do_set('audio_encoding foo')


def test_complete_set_audio_encoding(db, with_config, ripcmd):
assert completions(ripcmd, 'set audio_encoding z') == []
assert completions(ripcmd, 'set audio_encoding m') == ['mp3']
assert set(completions(ripcmd, 'set audio_encoding fl')) == {
'flac', 'flac16', 'flac24'}


def test_set_subtitle_format(db, with_config, ripcmd):
with db.transaction():
assert ripcmd.config.subtitle_format == 'none'
Expand Down
41 changes: 41 additions & 0 deletions tvrip/ripcmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def __init__(self, db, *, stdin=None, stdout=None):
'api_url': self.set_api_url,
'atomicparsley': self.set_executable,
'audio_all': self.set_bool,
'audio_encoding': self.set_audio_encoding,
'audio_langs': self.set_langs,
'audio_mix': self.set_audio_mix,
'decomb': self.set_decomb,
Expand Down Expand Up @@ -467,6 +468,7 @@ def do_config(self, arg=''):
table.add_row('decomb', self.config.decomb)
table.add_row('audio_mix', self.config.audio_mix)
table.add_row('audio_all', bool_str[self.config.audio_all])
table.add_row('audio_encoding', self.config.audio_encoding)
table.add_row('audio_langs', ' '.join(self.config.audio_langs))
table.add_row('subtitle_format', self.config.subtitle_format)
table.add_row('subtitle_all', bool_str[self.config.subtitle_all])
Expand Down Expand Up @@ -782,6 +784,45 @@ def set_complete_audio_mix(self, text, line, start, finish):

set_audio_mix.complete = set_complete_audio_mix

def set_audio_encoding(self, var, value):
"""
This configuration option specifies the audio encoder. Validd values
are "av_aac", "fdk_aac", "fdk_haac", "mp3", "vorbis", "opus", "flac16",
"flac24", "ac3", and "eac3"
"""
assert var == 'audio_encoding'
try:
value = {
'av-aac': 'av_aac',
'av_aac': 'av_aac',
'fdk-aac': 'fdk_aac',
'fdk_aac': 'fdk_aac',
'fdk-haac': 'fdk_haac',
'fdk_haac': 'fdk_haac',
'mp3': 'mp3',
'lame': 'mp3',
'vorbis': 'vorbis',
'opus': 'opus',
'flac': 'flac16',
'flac16': 'flac16',
'flac24': 'flac24',
'ac3': 'ac3',
'eac3': 'eac3',
}[value]
except KeyError:
raise CmdSyntaxError(f'Invalid audio encoding {value}')
else:
return var, value

def set_complete_audio_encoding(self, text, line, start, finish):
return self.set_complete_one(
line, start, {
'av-aac', 'av_aac', 'fdk-aac', 'fdk_aac', 'fdk-haac',
'fdk_haac', 'mp3', 'lame', 'vorbis', 'opus', 'flac', 'flac16',
'flac24', 'ac3', 'eac3'})

set_audio_encoding.complete = set_complete_audio_encoding

def set_subtitle_format(self, var, value):
"""
This configuration option specifies a subtitle format. Valid values
Expand Down
2 changes: 1 addition & 1 deletion tvrip/ripper.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def rip(self, config, episodes, title, audio_tracks, subtitle_tracks,
# audio encoding options (use 160kbps FDK-AAC plus whatever downmix
# the user selected for the specified tracks)
'-a', ','.join(str(num) for (num, _, _) in audio_defs),
'-E', ','.join('fdk_aac' for ad in audio_defs),
'-E', ','.join(config.audio_encoding for ad in audio_defs),
'-B', ','.join('160' for ad in audio_defs),
'-6', ','.join(mix for (_, mix, _) in audio_defs),
'-A', ','.join(name for (_, _, name) in audio_defs),
Expand Down
1 change: 1 addition & 0 deletions tvrip/var_audio_encoding.rst

0 comments on commit 3c8156e

Please sign in to comment.