Skip to content

Instantly share code, notes, and snippets.

@danielfomin96
Last active June 19, 2023 01:36
Show Gist options
  • Save danielfomin96/e79d223d0cb439fadd868edccce9a172 to your computer and use it in GitHub Desktop.
Save danielfomin96/e79d223d0cb439fadd868edccce9a172 to your computer and use it in GitHub Desktop.
ffmpeg wrapper to customely downmix videos opened by jellyfin
#!/bin/bash -
#title :ffmpeg
#description :This script is a wrapper for jellyfin ffmpeg to downmix audio to stereo using a custom formula
#author :Daniel Fomin
#date :20230104
#version :0.2
#reference :https://superuser.com/questions/852400/properly-downmix-5-1-to-stereo-using-ffmpeg
#
#
#==============================================================================
###############################################################################
# Installation Notes:
# 1. Put wrapper in directory accessible from jellyfin
# 2. `chmod +x path/to/wrapper/dir/ffmpeg`
# 3. `ln -s $(which ffprobe) path/to/wrapper/dir/` to the same directory
# 4. Point jellyfin to the wrapper directory
#
###############################################################################
function join { local IFS=$'\n'; echo "${*}"; }
args=$(join "${@}")
match='-ac\n[3-9]'
replace='-af\npan=stereo|FL<0.707*FC+0.707*FL+0.707*BL+0.5*LFE|FR<0.707*FC+0.707*FR+0.707*BR+0.5*LFE'
ffmpeg="/usr/lib/jellyfin-ffmpeg/ffmpeg"
readarray -t new_args < <(sed -z "s/$match/$replace/g" <<<"$args")
#echo "Command Rewrite: $ffmpeg $new_args" 1>&2
$ffmpeg "${new_args[@]}"
exit $?
@ManuLinares
Copy link

Thanks, will test this now as I have an older Firestick v1, and the latest (Master) jellyfin android tv app doesn't tell the server to downmix.

@ManuLinares
Copy link

I found something. (had some errors)

"TL;DR: if you have configured an alternative ffmpeg path in Jellyfin, make sure there's an ffprobe binary in the same location with the same file extension"

source

The errors

MediaBrowser.Providers.TV.EpisodeMetadataService: Error in ffprobe
System.ComponentModel.Win32Exception (2): No such file or directory

@danielfomin96
Copy link
Author

Is it enough to link the binary into the folder?

@ManuLinares
Copy link

yes.
ln -s `which ffprobe` /ffmpeg_wrapper_path/ffprobe

@danielfomin96
Copy link
Author

Thanks, this works great

@ejalal
Copy link

ejalal commented Jul 5, 2021

Hi @danielfomin96

Edit; forget this, I was using an earlier version of the script and updated to last revision, work like a charm, thanks for providing this

Any chance you can adapt the script to deep quotes if file path/names contain spaces as these are removed by parsing the args array

Example
/path/to/ffmpeg -fflags +genpts -i file:"/media/Movies/The Movie Example (2021)/The Movie Example (2021).mkv" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 copy -start_at_zero -vsync -1 -codec:a:0 aac -ac 6 -ab 640000 -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 6 -hls_segment_type mpegts -start_number 0 -hls_segment_filename "/config/transcodes/e8e57aa6a93c2ff1e1d3bb6de528a1d5%d.ts" -hls_playlist_type vod -hls_list_size 0 -y "/config/transcodes/e8e57aa6a93c2ff1e1d3bb6de528a1d5.m3u8"
Is converted to

/usr/lib/jellyfin-ffmpeg/ffmpeg -fflags +genpts -i file:/media/Movies/The Movie Example (2021)/The Movie Example (2021).mkv -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 copy -start_at_zero -vsync -1 -codec:a:0 aac -af pan=stereo|FL<0.707*FC+0.707*FL+0.707*BL+0.5*LFE|FR<0.707*FC+0.707*FR+0.707*BR+0.5*LFE -ab 640000 -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 6 -hls_segment_type mpegts -start_number 0 -hls_segment_filename /config/transcodes/e8e57aa6a93c2ff1e1d3bb6de528a1d5%d.ts -hls_playlist_type vod -hls_list_size 0 -y /config/transcodes/e8e57aa6a93c2ff1e1d3bb6de528a1d5.m3u8

@danielfomin96
Copy link
Author

Hi @danielfomin96

Edit; forget this, I was using an earlier version of the script and updated to last revision, work like a charm, thanks for providing this

Any chance you can adapt the script to deep quotes if file path/names contain spaces as these are removed by parsing the args array

Example
/path/to/ffmpeg -fflags +genpts -i file:"/media/Movies/The Movie Example (2021)/The Movie Example (2021).mkv" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 copy -start_at_zero -vsync -1 -codec:a:0 aac -ac 6 -ab 640000 -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 6 -hls_segment_type mpegts -start_number 0 -hls_segment_filename "/config/transcodes/e8e57aa6a93c2ff1e1d3bb6de528a1d5%d.ts" -hls_playlist_type vod -hls_list_size 0 -y "/config/transcodes/e8e57aa6a93c2ff1e1d3bb6de528a1d5.m3u8"
Is converted to

/usr/lib/jellyfin-ffmpeg/ffmpeg -fflags +genpts -i file:/media/Movies/The Movie Example (2021)/The Movie Example (2021).mkv -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 copy -start_at_zero -vsync -1 -codec:a:0 aac -af pan=stereo|FL<0.707*FC+0.707*FL+0.707*BL+0.5*LFE|FR<0.707*FC+0.707*FR+0.707*BR+0.5*LFE -ab 640000 -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time 6 -hls_segment_type mpegts -start_number 0 -hls_segment_filename /config/transcodes/e8e57aa6a93c2ff1e1d3bb6de528a1d5%d.ts -hls_playlist_type vod -hls_list_size 0 -y /config/transcodes/e8e57aa6a93c2ff1e1d3bb6de528a1d5.m3u8

Are you using the newest revision?

@ManuLinares
Copy link

echo will remove quotes, but the command is working nevertheless. to debug a bash script, add "set -x" to the top.
There you can see the quotes are there.

@ejalal
Copy link

ejalal commented Jul 6, 2021

Yep, works great with the latest version of the script.

Is it possible to add an option to use a 2.1 system instead of stereo, it sounds already waaaaaay better than the previous "-ac 2" but a bit dull without a proper LFE channel

@danielfomin96
Copy link
Author

This script is just an example which everybody can fit to their own liking.
The channel formula is specified in the replace variable. In your case, try to append something like |LFE=LFE to the variable, maybe it will work.

@mark-cassidy
Copy link

Thanks for this was trying to write something similar - your foo is much stronger than my bar!

Couple of notes for future noobish users like myself

the "ln -s" command creates a symbolic link for ffprobe - my unraid docker container didn't recognise the "which" command, I had to use:

ln -s /usr/lib/jellyfin-ffmpeg/ffmpeg/ffprobe /config/

where I placed the script in the config directory

another nooby issue is that i forgot to set permissions:

chmod u=rwx,g=rwx,o=rwx /config/ffmpeg

Hope this helps someone!

@ManuLinares
Copy link

I'll leave here an improved version or the wrapper script, with proper handling of quotes

#!/bin/bash -
#title           :ffmpeg wrapper
#description     :This script is a wrapper for jellyfin ffmpeg to replace arguments
#==============================================================================

ffmpeg="/usr/lib/jellyfin-ffmpeg/ffmpeg"

#Add quotes for arguments with "spaces" and "round brackets")
for x in "${@}" ; do
    # try to figure out if quoting was required for the $x (Arguments)
    if [[ "$x" != "${x%[[:space:]]*}" ]] \
    || [[ "$x" != "${x%(*}" ]] ; then
        x="\""$x"\""
    fi
    _args=$_args" "$x
done

# Downmix audio to stereo
_args=${_args/-ac [3-9]/-af \"pan=stereo|FL < 0.5*FC + 0.3*FLC + 0.3*FL + 0.3*BL + 0.3*SL + 0.5*LFE | FR < 0.5*FC + 0.3*FRC + 0.3*FR + 0.3*BR + 0.3*SR + 0.5*LFE,volume=2\"}

eval $ffmpeg $_args

exit $?

@danielfomin96
Copy link
Author

Thanks for this was trying to write something similar - your foo is much stronger than my bar!

Couple of notes for future noobish users like myself

the "ln -s" command creates a symbolic link for ffprobe - my unraid docker container didn't recognise the "which" command, I had to use:

ln -s /usr/lib/jellyfin-ffmpeg/ffmpeg/ffprobe /config/

where I placed the script in the config directory

another nooby issue is that i forgot to set permissions:

chmod u=rwx,g=rwx,o=rwx /config/ffmpeg

Hope this helps someone!

Thank you @mark-cassidy for your remarks, I have added the chmod command to the installation notes.

@ivaylo-mk
Copy link

Real noob question, but I stumbled upon your script and I am wondering if it is possible to use it somehow in Windows, as currently I am experiencing issues with Jellyfin and 5.1 audio, and want to force downmixing to stereo of everything that is being played.

@mark-cassidy
Copy link

mark-cassidy commented Jan 22, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment