mdhiggins / sickbeard_mp4_automator

Automatically convert video files to a standardized format with metadata tagging to create a beautiful and uniform media library
MIT License
1.5k stars 206 forks source link

Universal Surround Audio #1692

Closed SenorSmartyPants closed 6 months ago

SenorSmartyPants commented 6 months ago

Is your feature request related to a problem? Please describe. Surround audio incompatible with current audio receiver. Would like to keep more modern surround formats as well as a new compatible one.

Describe the solution you'd like Similar to Universal Audio function to generate a stereo track, but this would generate surround track if there wasn't one in the selected codec.

Describe alternatives you've considered I've worked on this some my own in #1681 and as far as I can figure out this would require main source code changes (I don't think I can override with existing options using validate custom function)

mdhiggins commented 6 months ago

How would this be different than the base functionality that already handles the surround tracks?

SenorSmartyPants commented 6 months ago

I have different acceptable codecs for stereo or surround. Stereo: aac, ac3 Surround: ac3

I have currently found no way to handle all these options, generating only 1 new AC3 surround track (if one does not exist) and keep all original audio tracks. Universal Audio seems like it does exactly that but just for stereo.

mdhiggins commented 6 months ago

The audio copy original option is what you're looking I think

Does exactly what you're describing

Define your stereo codecs in universal

Define your surround codecs in regular audio options

Turn on copy original if you always want the original track preserved

SenorSmartyPants commented 6 months ago

I don't want additional stereo tracks if none already exist. Just to preserve the existing stereo tracks. autoprocess.ini

[Audio]
codec = ac3
languages =
default-language =
include-original-language = True
first-stream-of-language = False
channel-bitrate = 128
variable-bitrate = 0
max-bitrate = 0
max-channels = 0
filter =
profile =
force-filter = False
sample-rates =
sample-format =
copy-original = True
aac-adtstoasc = False
ignored-dispositions =
force-default = False
unique-dispositions = False
stream-codec-combinations =

[Universal Audio]
codec = aac, ac3
channel-bitrate = 128
variable-bitrate = 0
first-stream-only = False
filter =
profile =
force-filter = False

Test cases: Input

        "audio": [
            {
                "index": 1,
                "codec": "aac",
                "bitrate": 224000,
                "channels": 6,
                "samplerate": 48000,
                "language": "eng",
                "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions"
            }
        ],

Output - includes Universal Audio, naturally, but not one I want.

        "audio": [
            {
                "map": 1,
                "codec": "ac3",
                "channels": 6,
                "bitrate": 768,
                "profile": null,
                "quality": 0,
                "filter": null,
                "samplerate": null,
                "sampleformat": "",
                "language": "eng",
                "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",
                "bsf": null,
                "debug": "audio",
                "title": "5.1 Channel"
            },
            {
                "map": 1,
                "codec": "copy",
                "bitrate": 224.0,
                "channels": 6,
                "language": "eng",
                "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",
                "debug": "audio-copy-original",
                "title": "5.1 Channel"
            },
            {
                "map": 1,
                "codec": "aac",
                "channels": 2,
                "bitrate": 256,
                "quality": 0,
                "profile": null,
                "samplerate": null,
                "sampleformat": "",
                "filter": null,
                "language": "eng",
                "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",
                "debug": "universal-audio",
                "title": "Stereo"
            }
        ],

Input

        "audio": [
            {
                "index": 1,
                "codec": "ac3",
                "bitrate": 256000,
                "channels": 6,
                "samplerate": 48000,
                "language": "eng",
                "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions"
            },
            {
                "index": 2,
                "codec": "aac",
                "bitrate": 128001,
                "channels": 2,
                "samplerate": 48000,
                "language": "eng",
                "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions"
            }
        ],

Output - Creates UA where it doesn't seem to be needed.

        "audio": [
            {
                "map": 1,
                "codec": "copy",
                "channels": 6,
                "bitrate": 768,
                "profile": null,
                "quality": 0,
                "filter": null,
                "samplerate": null,
                "sampleformat": "",
                "language": "eng",
                "disposition": "+default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",
                "bsf": null,
                "debug": "audio",
                "title": ""
            },
            {
                "map": 1,
                "codec": "aac",
                "channels": 2,
                "bitrate": 256,
                "quality": 0,
                "profile": null,
                "samplerate": null,
                "sampleformat": "",
                "filter": null,
                "language": "eng",
                "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",
                "debug": "universal-audio",
                "title": ""
            },
            {
                "map": 2,
                "codec": "copy",
                "channels": 2,
                "bitrate": 256,
                "profile": null,
                "quality": 0,
                "filter": null,
                "samplerate": null,
                "sampleformat": "",
                "language": "eng",
                "disposition": "-default-dub-original-comment-lyrics-karaoke-forced-hearing_impaired-visual_impaired-captions",
                "bsf": null,
                "debug": "universal-audio",
                "title": ""
            }
        ],
mdhiggins commented 6 months ago

So it seems like you just want to adjust your codec pool just based on the number of channels, this should be pretty easy with a custom function

skipStream is run at the start of processing each stream, so you can adjust your settings in that function

def skipStream(mp, stream, info, path, tagdata):
    if stream.type == "audio":
        if stream.audio_channels == 2:
            mp.settings.acodec = ['aac', 'ac3']
        else:
            mp.settings.acodec = ['ac3']
        self.log.debug("Modified pool of audio codecs is %s." % (mp.settings.acodec))
    return False
SenorSmartyPants commented 6 months ago

Thank you for the help. I based my code on your example and it was working well until I ran into some multi language files. I changed my audio language options to only keep english and I noticed that skipStream runs before filtering out languages. I'm checking all the audio tracks and filtering the languages now in the validate method. So I can reject changing files for cases I'm not handling yet. Seems to do what I want for what I've tested so far.

def validation(mp, info, path, tagdata):
    mp.log.info("Initiating custom validation method.")
    audiotracks = info.audio
    if len(audiotracks) == 1:
        #TODO: more stereo audio codecs that are compatible with NMT. vorbis?
        if audiotracks[0].audio_channels == 2:
            mp.settings.acodec = ["aac","ac3"]
            mp.log.info("Single stereo audio track. Modified pool of audio codecs is %s." % (mp.settings.acodec))
        return True
    else:
        mp.log.info("Video has more than 1 audio stream.")
        AC3SurroundFound = False
        acodecs = []
        validTrackCount = 0
        awl = mp.settings.awl
        for audio in audiotracks:
            if mp.validLanguage(audio.metadata['language'], awl, []):
                mp.log.info("Audio Track: %s %s %s channels" % (audio.metadata['language'], audio.codec, audio.audio_channels))
                validTrackCount += 1
                if audio.codec not in acodecs:
                    acodecs.append(audio.codec)
                if audio.codec == 'ac3' and audio.audio_channels == 6:
                    AC3SurroundFound = True

        mp.log.info("Valid audio track count is %i." % (validTrackCount))
        if AC3SurroundFound:
            #keep all audio, let SMA process as normal
            mp.settings.acodec = acodecs
            mp.log.info("AC3 5.1 found, keeping all audio. Modified pool of audio codecs is %s." % (mp.settings.acodec))
        return AC3SurroundFound or validTrackCount == 1
mdhiggins commented 6 months ago

Thanks for sharing, closing this out