Skip to content

Instantly share code, notes, and snippets.

@gaborbata
Last active January 12, 2023 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gaborbata/23c3de70ba15c2e0d28c4fdbc3c9fadb to your computer and use it in GitHub Desktop.
Save gaborbata/23c3de70ba15c2e0d28c4fdbc3c9fadb to your computer and use it in GitHub Desktop.
Convenience methods for ffmpeg
#!/usr/bin/env ruby
# Convenience methods for ffmpeg
# Character encoding of subtitle
SUB_ENCODING = 'ISO-8859-2'
# Subtitle language
SUB_LANG = 'hun'
# List of supported commands
COMMANDS = {
'embedsrt' => lambda do |args| embed_srt(args) end,
'normalize' => lambda do |args| normalize_audio end,
'extract_audio' => lambda do |args| extract_audio end,
'help' => lambda do |args| puts "supported commands: #{COMMANDS.keys.join(', ')}" end
}
# Embed srt subtitles into video files
def embed_srt(args)
encoding = args[0] || SUB_ENCODING
puts 'Subtitle encoding: ' + encoding
Dir.glob('*.{mp4,avi,mkv}').sort.each do |video_file|
ext = File.extname(video_file)
name = File.basename(video_file, ext)
if !File.exist?(name + '.srt')
puts "Skipping '#{name}' due to missing subtitle"
next
end
# remove previous subtitles
if ext == '.avi'
system("ffmpeg -fflags +genpts -i \"#{name}#{ext}\" -vcodec copy -acodec copy -sn \"#{name}_temp.mkv\"")
else
system("ffmpeg -i \"#{name}#{ext}\" -vcodec copy -acodec copy -sn \"#{name}_temp.mkv\"")
end
# add subtitle
system("ffmpeg -i \"#{name}_temp.mkv\" -sub_charenc #{encoding} -i \"#{name}.srt\" -vcodec copy -acodec copy -scodec srt -metadata:s:s:0 language=#{SUB_LANG} -disposition:s:0 default \"#{name}_sub.mkv\"")
# delete temporary file
system("rm -v \"#{name}_temp.mkv\"")
end
end
# normalze audio in video files
def normalize_audio
Dir.glob('*.{mp4,avi,mkv}').each do |file|
system("ffmpeg -i \"#{file}\" -vcodec copy -ac 2 -af dynaudnorm -acodec aac '#{file}_norm.mp4'")
end
end
# extract m4a audio from mp4 video files
def extract_audio
Dir.glob("*.mp4").each do |file|
system("ffmpeg.exe -i #{file} -vn -acodec copy #{file.sub('.mp4', '.m4a')}")
end
end
# TODO concat video files
# $ ffmpeg -f concat -safe 0 -i files.txt -c copy output.mkv
#
# $ cat files.txt
# file 'file 1.mkv'
# file 'file 2.mkv'
# file 'file 3.mkv'
# file 'file 4.mkv'
# TODO convert to mp3 music
# $ ffmpeg -i input.webm -vn -acodec mp3 -q:a 4 output.mp3
# $ ffmpeg -i file.mp3 -metadata title="Track Title" -metadata artist="Rockstar" -metadata album="Hot Shit" out.mp3
# Extract srt from files
# ffmpeg -i #{file} -vn -an -codec:s:0.1 srt #{file.gsub('.mkv', '')}.srt
# Convert to vp9
# ffmpeg -i #{file} -c:v libvpx-vp9 -crf 22 -g 240 -b:v 0 -ac 2 -acodec libopus -b:a 112k #{file}.webm
# this may have keyframe compression flickering: https://groups.google.com/a/webmproject.org/g/webm-discuss/c/GwsvXJUhyq0
# two-pass vp9 example
# ffmpeg -i s1.mkv -vf "crop=960:540" -c:v libvpx-vp9 -b:v 1800k -minrate 900k -maxrate 2610k -g 240 -pass 1 -speed 4 -an -sn -f null /dev/null && ffmpeg -i s1.mkv -vf "crop=960:540" -c:v libvpx-vp9 -b:v 1800k -minrate 900k -maxrate 2610k -g 240 -an -sn -pass 2 -speed 2 o1.webm
# Convert to x265
# ffmpeg -i #{file} -c:v libx265 -crf 19 -ac 2 -acodec aac -b:a 112k #{file}.mp4
# merge audio and video
# ffmpeg -i video.mkv -i audio.mkv -c:v copy -c:a copy -map 0:v:0 -map 1:a:0 output.mkv
# with delay
# system("ffmpeg -i #{e[0]} -itsoffset 0.5 -i #{e[1]} -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 out2/#{e[0]}")
# You can 'simply' convert the current fps to the desired one using the 'atempo' filter. For example, to achieve a common conversion from PAL (25fps) to NTSC (23.976fps) would be:
# 23.976/25 = 0.95904
# So with ffmpeg:
# ffmpeg -i input.mkv -filter:a "atempo=0.95904" -af -vn out.mkv
# You would also to apply a different most efficient codec. For example maintaing previous parameters but adding codec options: Opus, 224kbps VBR, 5.1 channels:
# ffmpeg -i input.mkv -filter:a "atempo=0.95904" -c:a libopus -b:a 224k -vbr 1 -af "ch
command = COMMANDS[ARGV[0]] || COMMANDS['help']
command.call(ARGV[1..-1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment