Last active
August 29, 2015 14:12
-
-
Save Shudouken/3796ec60ebd6d42f5d00 to your computer and use it in GitHub Desktop.
Convert Script - ffmpeg edition
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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