Skip to content

Instantly share code, notes, and snippets.

@Shudouken
Last active August 29, 2015 14:12
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shudouken/3796ec60ebd6d42f5d00 to your computer and use it in GitHub Desktop.
Save Shudouken/3796ec60ebd6d42f5d00 to your computer and use it in GitHub Desktop.
Convert Script - ffmpeg edition
-- README:
-- original version by Zehkul https://gist.github.com/Zehkul/25ea7ae77b30af959be0
-- needs: yad, libnotify, imagemagick (and ytdl if you want to encode streams)
-- press any of alt + w, g, x or c to set the start frame
-- press again to set the end frame and use
-- alt + w to make a webm
-- alt + g to make a gif
-- alt + x to make a x264 encoded mkv
-- alt + c to make a direct stream copy saved into mkv (fast but start time may be off due to keyframes)
-- alt + 5 to make a experimental x265 encoded mkv
-- Note: encoding a webm to a specific filesize will only work if audio is disabled
-- and including subs will make them lose their styling
local mputils = require 'mp.utils'
-- Options
-- to make sure the file won't go over the target file size, set it to 1 if you don't care
bitrate_multiplier = 0.975
-----------------
-- Main script --
-----------------
-- sets start and end frame of the portion to encode and calls the respective gui
function set_timepos(call_gui)
if timepos1 then
timepos2 = mp.get_property("time-pos")
if tonumber(timepos1) > tonumber(timepos2) then
length = timepos1-timepos2
start = timepos2
--mp.osd_message("End frame set")
elseif tonumber(timepos2) > tonumber(timepos1) then
length = timepos2-timepos1
start = timepos1
--mp.osd_message("End frame set")
else
mp.osd_message("Both frames are the same, ignoring the second one", 3)
timepos2 = nil
return
end
timepos1 = nil
mp.set_property("fullscreen", "no")
mp.set_property("ontop", "no")
call_gui()
else
timepos1 = mp.get_property("time-pos")
mp.osd_message("Start frame set")
end
end
------------
-- Encode --
------------
-- checks and generates input and output filenames
function generate_filenames(ext)
local filename_ext = mp.get_property_osd("filename")
filename_ext = string.gsub(filename_ext, "'", "'\\''")
local filename = string.gsub(filename_ext, "%....$","")
local dir, fil = mputils.split_path(mp.get_property("path", ""))
file_in = mp.get_property("stream-open-filename")
file_in = string.gsub(file_in, "'", "'\\''")
out = os.date("-%d%m%y-%H:%M:%S.")
--check for ytdl-stream
if string.sub(file_in,1,4) == "http" then
file_out = os.getenv("HOME") .. "/" .. mp.get_property("media-title") .. out .. ext
file_out = string.gsub(file_out, "'", "'\\''")
else
file_out = dir .. filename .. out .. ext
end
end
function encode_webm ()
generate_filenames("webm")
local full_command = '(ffmpeg -ss ' .. start .. ' -i \'' .. file_in .. '\' -t ' .. length .. ' -b:v ' .. bitrate .. bitsize .. ' -vf scale=' .. scale .. ':-1 -quality good -cpu-used 0 -pass 1 ' .. audio .. ' ' .. subs .. ' -f webm /dev/null -y'
full_command = full_command .. ' && ffmpeg -ss ' .. start .. ' -i \'' .. file_in .. '\' -t ' .. length .. ' -b:v ' .. bitrate .. bitsize .. ' -vf scale=' .. scale .. ':-1 -quality good -cpu-used 0 -pass 2 ' .. audio .. ' ' .. subs .. ' -f webm \'' .. file_out .. '\' -y && rm ffmpeg2pass*.log'
full_command = full_command .. ') && notify-send "Encode done!"'
mp.osd_message("Webm encode started")
os.execute(full_command)
end
function encode_gif ()
generate_filenames("gif")
local full_command = '(ffmpeg -ss ' .. start .. ' -i \'' .. file_in .. '\' -t ' .. length .. ' -vf scale=' .. scale .. ':-1 -r ' .. fps .. ' -f image2pipe -vcodec ppm - | convert -delay 1x' .. fps .. ' -loop 0 - gif:- | convert -layers Optimize - \'' .. file_out .. '\''
full_command = full_command .. ') && notify-send "Encode done!"'
mp.osd_message("Gif encode started")
os.execute(full_command)
end
function encode_x264 ()
generate_filenames("mkv")
local full_command = '(ffmpeg -ss ' .. start .. ' -i \'' .. file_in .. '\' -t ' .. length .. ' -c:v libx264 -vf scale=' .. sheight .. ':' .. swidth .. ' -preset slow -qp ' .. quality .. ' ' .. audio .. ' ' .. subs .. ' ' .. attachments .. ' \'' .. file_out .. '\' -y'
full_command = full_command .. ') && notify-send "Encode done!"'
mp.osd_message("Mkv(x264) encode started")
os.execute(full_command)
end
function encode_x265 ()
generate_filenames("mkv")
local full_command = '(ffmpeg -ss ' .. start .. ' -i \'' .. file_in .. '\' -t ' .. length .. ' -c:v libx265 -vf scale=' .. sheight .. ':' .. swidth .. ' -preset slow -x265-params qp=' .. quality .. ' -strict experimental ' .. audio .. ' ' .. subs .. ' ' .. attachments .. ' \'' .. file_out .. '\' -y'
full_command = full_command .. ') && notify-send "Encode done!"'
mp.osd_message("Mkv(x265) encode started")
os.execute(full_command)
end
function encode_copy ()
mp.resume_all()
generate_filenames("mkv")
local full_command = '(ffmpeg -ss ' .. start .. ' -i \'' .. file_in .. '\' -t ' .. length .. ' -c:v copy -c:a copy -c:s copy -map 0 \'' .. file_out .. '\' -y'
full_command = full_command .. ') && notify-send "Encode done!"'
mp.osd_message("Mkv(copy) encode started")
os.execute(full_command)
end
---------
-- GUI --
---------
function call_gui_webm ()
mp.resume_all()
local handle = io.popen('yad --title="Convert Script" --center --form --separator="\n" --field="Resize to:NUM" "720" --field="Don’t resize at all:CHK" "false" --field="Include audio:CHK" "false" --field="Include subs:CHK" "false" --field="Bitrate/Filesize (M):NUM" "4" --field="Filesize > Bitrate:CHK" "true" --button="gtk-cancel:2" --button="gtk-ok:0" && echo "$?"')
local yad = handle:read("*a")
handle:close()
--yad not installed/available, using standard settings
if yad == "" then
scale = "720"
audio = "-an"
subs = "-sn"
bitrate = math.floor(4*1024*8/length*bitrate_multiplier)
bitsize = "K"
encode_webm()
return
end
local yad_table = {}
local i = 0
for k in string.gmatch(yad, "[%a%d]+") do
yad_table[i] = k
i = i + 1
end
if (yad_table[2] == "FALSE") then
scale = yad_table[0]
else
scale = "-1"
end
if yad_table[3] == "FALSE" then
audio = '-an'
else
audio = "-aq 0"
end
if yad_table[4] == "FALSE" then
subs = '-sn'
else
subs = ""
end
if yad_table[7] == "TRUE" then
bitrate = math.floor(yad_table[5]*1024*8/length*bitrate_multiplier)
bitsize = "K"
else
bitrate = yad_table[5]
bitsize = "M"
end
if yad_table[8] == "0" then
encode_webm()
end
end
function call_gui_gif ()
mp.resume_all()
local handle = io.popen('yad --title="Convert Script" --center --form --separator="\n" --field="Resize to:NUM" "320" --field="Don’t resize at all:CHK" "false" --field="FPS:NUM" "24" --button="gtk-cancel:2" --button="gtk-ok:0" && echo "$?"')
local yad = handle:read("*a")
handle:close()
--yad not installed/available, using standard settings
if yad == "" then
scale = "320"
fps = "24"
encode_gif()
return
end
local yad_table = {}
local i = 0
for k in string.gmatch(yad, "[%a%d]+") do
yad_table[i] = k
i = i + 1
end
if (yad_table[2] == "FALSE") then
scale = yad_table[0]
else
scale = "-1"
end
fps = yad_table[3]
if fps == "0" then
mp.osd_message("Error: framerate can't be zero", 3)
return
end
if yad_table[5] == "0" then
encode_gif()
end
end
function call_gui_x264 ()
mp.resume_all()
local handle = io.popen('yad --title="Convert Script" --center --form --separator="\n" --field="Resize height:NUM" "720" --field="Resize width:NUM" "480" --field="Don’t resize at all:CHK" "true" --field="Quality (0-51):NUM" "18" --field="Include audio:CHK" "true" --field="Include subs:CHK" "true" --field="Include attachments:CHK" "false" --button="gtk-cancel:2" --button="gtk-ok:0" && echo "$?"')
local yad = handle:read("*a")
handle:close()
--yad not installed/available, using standard settings
if yad == "" then
sheight = "-1"
swidth = "-1"
quality = "18"
audio = "-c:a copy"
subs = "-c:s copy"
attachments = ""
encode_x264()
return
end
local yad_table = {}
local i = 0
for k in string.gmatch(yad, "[%a%d]+") do
yad_table[i] = k
i = i + 1
end
if (yad_table[4] == "FALSE") then
sheight = yad_table[0]
else
sheight = "-1"
end
if (yad_table[4] == "FALSE") then
swidth = yad_table[2]
else
swidth = "-1"
end
if ((sheight ~= "-1" and swidth ~= "-1") and (tonumber(sheight)%2 ~= 0 or tonumber(swidth)%2 ~= 0)) then
mp.osd_message("Error: not divisible by 2 (" .. sheight .. ":" .. swidth .. ")", 3)
return
end
quality = yad_table[5];
if (yad_table[7] == "TRUE") then
audio = "-c:a copy"
else
audio = "-an"
end
if (yad_table[8] == "TRUE") then
subs = "-c:s copy"
else
subs = "-sn"
end
if (yad_table[9] == "TRUE") then
attachments = "-map 0"
else
attachments = ""
end
if yad_table[10] == "0" then
encode_x264()
end
end
function call_gui_x265 ()
mp.resume_all()
local handle = io.popen('yad --title="Convert Script" --center --form --separator="\n" --field="Resize height:NUM" "720" --field="Resize width:NUM" "480" --field="Don’t resize at all:CHK" "true" --field="Quality (0-51):NUM" "18" --field="Include audio:CHK" "true" --field="Include subs:CHK" "true" --field="Include attachments:CHK" "false" --button="gtk-cancel:2" --button="gtk-ok:0" && echo "$?"')
local yad = handle:read("*a")
handle:close()
--yad not installed/available, using standard settings
if yad == "" then
sheight = "-1"
swidth = "-1"
quality = "18"
audio = "-c:a copy"
subs = "-c:s copy"
attachments = ""
encode_x265()
return
end
local yad_table = {}
local i = 0
for k in string.gmatch(yad, "[%a%d]+") do
yad_table[i] = k
i = i + 1
end
if (yad_table[4] == "FALSE") then
sheight = yad_table[0]
else
sheight = "-1"
end
if (yad_table[4] == "FALSE") then
swidth = yad_table[2]
else
swidth = "-1"
end
if ((sheight ~= "-1" and swidth ~= "-1") and (tonumber(sheight)%2 ~= 0 or tonumber(swidth)%2 ~= 0)) then
mp.osd_message("Error: not divisible by 2 (" .. sheight .. ":" .. swidth .. ")", 3)
return
end
quality = yad_table[5];
if (yad_table[7] == "TRUE") then
audio = "-c:a copy"
else
audio = "-an"
end
if (yad_table[8] == "TRUE") then
subs = "-c:s copy"
else
subs = "-sn"
end
if (yad_table[9] == "TRUE") then
attachments = "-map 0"
else
attachments = ""
end
if yad_table[10] == "0" then
encode_x265()
end
end
mp.add_key_binding("alt+w", "convert_script_webm", function() set_timepos(call_gui_webm) end)
mp.add_key_binding("alt+g", "convert_script_gif", function() set_timepos(call_gui_gif) end)
mp.add_key_binding("alt+x", "convert_script_x264", function() set_timepos(call_gui_x264) end)
mp.add_key_binding("alt+5", "convert_script_x265", function() set_timepos(call_gui_x265) end)
mp.add_key_binding("alt+c", "convert_script_copy", function() set_timepos(encode_copy) end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment