How to monitor progress from ffmpeg? - ruby-on-rails

I have this ffmpeg video encoder using Rails and I needed to report ffmpeg progress to the user.
How can that be done provided that I am using Linux?

This is the solution I reached:
def execute_ffmpeg(cmd, progress)
logger.debug "Running command #{cmd}"
command = "#{cmd} 2>&1"
progress = nil
frames = nil
fps = 25
ffmpeg = IO.popen(command)
ffmpeg.each("\r") do |line|
if frames.nil? && line =~ /Duration:(\s.?(\d*):(\d*):(\d*\.\d*))/
duration = $2.to_s + ":" + $3.to_s + ":" + $4.to_s
frames = ($4.to_i + ($3.to_i * 60) + ($2.to_i * 60 * 60)) * fps
end
if line =~ /frame=(\s.?(\d*))/
progress = $1.to_i / frames.to_i
print "Progress: #{progress}"
end
end
end

Thanks for the post, I modified it a little. I am using ffmpeg version 0.10.2. Here's my version:
def exec_ffmpeg src_path, dst_path
cmd = "ffmpeg -i \"%s\" -acodec libfaac -ac 2 -ab 128k -vcodec libx264 -threads 0 \"%s\" 2>&1" %
[src_path, dst_path]
puts "%s" % cmd.gsub(/2\>\&1$/,'')
puts "press 'q' to quit"
progress = nil
dur_secs = nil
frame_rate = nil
frames = 0
dur_str = '00:00:00.000'
ostr = ''
ffmpeg = IO.popen(cmd)
ffmpeg.each("\r") do |line|
if dur_secs == nil && line =~ /Duration:\s*(\d*):(\d*):(\d*\.\d*)/
dur_str = $1.to_s + ":" + $2.to_s + ":" + $3.to_s
dur_secs = ($3.to_f + ($2.to_i * 60).to_f + ($1.to_i * 360).to_f)
puts "Video Duration:" + dur_str
end
if frame_rate == nil && line =~ /Stream.+\, (\d+\.{0,1}\d{0,3}) fps\,/
frame_rate = $1.to_f
frames = dur_secs * frame_rate
puts "Total Frames: %i" % frames.to_i
puts "Frame Rate: %.3f fps" % frame_rate
end
if line =~ /frame=(\s.?(\d*))/
cframe = $1.to_i
csecs = 0
if line =~ /time=\s*(\d*):(\d*):(\d*\.\d*)/
csecs = ($3.to_f + ($2.to_i * 60).to_f + ($1.to_i * 360).to_f)
csecs_str = $1.to_s + ":" + $2.to_s + ":" + $3.to_s
elsif line =~ /time=\s*(\d*\.\d*)/
csecs $1.to_f
t = Time.at(csecs).gmtime
csecs_str = "%0.2i:%0.2i:%0.2i.%3i" % [t.hour, t.min, t.sec, t.nsec]
end
if line =~ /fps=\s*(\d*)/
cfps = $1.to_i
else
cfps = 0
end
if line =~ /bitrate=\s*(\d*\.\d*kbits)/
br = $1
else
br = "???"
end
ostr = " %3.2f%% ( %s ) #frame:%i fps:%i bitrate:%s" %
[((csecs/dur_secs)*100), csecs_str, cframe, cfps, br]
print ostr + ("\b" * (ostr.length + 4))
end
end
print "\n"
end

Related

problem with 3d rastarizer in lua z dimension is not working

so basicaly i try to translate olc3d engine from cpp to lua in computercraft in minecraft
i can translate the cube in x and y but z does not work
this is the original olc3d engine that i try to copy
https://github.com/OneLoneCoder/videos/blob/master/OneLoneCoder_olcEngine3D_Part1.cpp
function newLine()
xPos, yPos = term.getCursorPos()
term.setCursorPos(1,(yPos + 1))
end
paitutils2.newMonitor("left")
mesh = {
{vector.new(0.0,0.0,0.0),vector.new(0.0,1.0,0.0),vector.new(1.0,1.0,0.0)},
{vector.new(0.0,0.0,0.0),vector.new(1.0,1.0,0.0),vector.new(1.0,0.0,0.0)},
{vector.new(1.0,0.0,0.0),vector.new(1.0,1.0,0.0),vector.new(1.0,1.0,1.0)},
{vector.new(1.0,0.0,0.0),vector.new(1.0,1.0,1.0),vector.new(1.0,0.0,1.0)},
{vector.new(1.0,0.0,1.0),vector.new(1.0,1.0,1.0),vector.new(0.0,1.0,1.0)},
{vector.new(1.0,0.0,1.0),vector.new(0.0,1.0,1.0),vector.new(0.0,0.0,1.0)},
{vector.new(0.0,0.0,1.0),vector.new(0.0,1.0,1.0),vector.new(0.0,1.0,0.0)},
{vector.new(0.0,0.0,1.0),vector.new(0.0,1.0,0.0),vector.new(0.0,0.0,0.0)},
{vector.new(0.0,1.0,0.0),vector.new(0.0,1.0,1.0),vector.new(1.0,1.0,1.0)},
{vector.new(0.0,1.0,0.0),vector.new(1.0,1.0,1.0),vector.new(1.0,1.0,0.0)},
{vector.new(1.0,0.0,1.0),vector.new(0.0,0.0,1.0),vector.new(0.0,0.0,0.0)},
{vector.new(1.0,0.0,1.0),vector.new(0.0,0.0,0.0),vector.new(1.0,0.0,0.0)}
}
matrix = {{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}}
matproj = matrix
wysokosc = 80.0
szerokosc = 164.0
fnear = 0.1
ffar = 1000.0
ffov = 90.0
fasr = (wysokosc/szerokosc)* (7/5) --because 'pixel' is 7x5 pixels
ffovr = 1.0 / math.tan(ffov * 0.5 / 180.0 * math.pi)
w=1
--3dpespective matrix
matproj[1][1] = fasr * ffovr
matproj[2][2] = ffovr
matproj[3][3] = -ffar / (ffar - fnear)
matproj[4][3] = (-ffar * fnear)/(ffar - fnear)
matproj[3][4] = -1.0
matproj[4][4] = 0.0
function proj_mat(matrix ,trj)
proj_tri = vector.new()
--print(trj.x .." ".. trj.y .." " .. trj.z )
proj_tri.x = (trj.x * matrix[1][1]) + (trj.y * matrix[2][1]) + (trj.z * matrix[3][1] )+ w * matrix[4][1]
proj_tri.y = (trj.x * matrix[1][2]) + (trj.y * matrix[2][2]) + (trj.z * matrix[3][2] )+ w * matrix[4][2]
proj_tri.z = (trj.x * matrix[1][3]) + (trj.y * matrix[2][3]) + (trj.z * matrix[3][3] )+ w * matrix[4][3]
w = (trj.x * matrix[1][4]) + (trj.y * matrix[2][4]) + (trj.z * matrix[3][4] )+ w * matrix[4][4]
if not w == 0.0 then
proj_tri.x = proj_tri.x / w
proj_tri.y = proj_tri.y / w
proj_tri.z = proj_tri.z / w
end
print(proj_tri.x .." ".. proj_tri.y .." " .. proj_tri.z .." ".. trj.x .." ".. trj.y .. " " .. trj.z)
return(proj_tri)
end
peripheral.call("left","setBackgroundColor",colors.black)
peripheral.call("left","setCursorBlink",false)
peripheral.call("left","setTextScale",0.5)
peripheral.call("left","clear")
peripheral.call("left","setBackgroundColor",colors.red)
for i = 1 , 12 ,1 do
vert = {}
vert[1] = mesh[i][1]
vert[2] = mesh[i][2]
vert[3] = mesh[i][3]
--print(vert[1].x .." ".. vert[1].y.." " .. vert[1].z .. " "..vert[2].x .." ".. vert[2].y.." " .. vert[2].z .." ".. vert[3].x .." ".. vert[3].y.." " .. vert[3].z)
vert[1].z = vert[1].z + 3.0
vert[2].z = vert[2].z + 3.0 --translacja
vert[3].z = vert[3].z + 3.0
vert[1].x = vert[1].x + 0.25
vert[2].x = vert[2].x + 0.25 --translacja
vert[3].x = vert[3].x + 0.25
--vert[1].y = vert[1].y + 0.5
--vert[2].y = vert[2].y + 0.5 --translacja
--vert[3].y = vert[3].y + 0.5
--print(vert[1].x .." ".. vert[1].y.." " .. vert[1].z .. " | "..vert[2].x .." ".. vert[2].y.." " .. vert[2].z .." | ".. vert[3].x .." ".. vert[3].y.." " .. vert[3].z)
proj_vert = vector.new()
-- proj_vert[1] = proj_mat(rotx,vert[1])
-- proj_vert[2] = proj_mat(rotx,vert[2]) --rotate x
-- proj_vert[3] = proj_mat(rotx,vert[3])
proj_vert[1] = proj_mat(matproj,vert[1])
proj_vert[2] = proj_mat(matproj,vert[2]) --projekcja 3d na 2d
proj_vert[3] = proj_mat(matproj,vert[3])
--skalowanie
proj_vert[1].x = proj_vert[1].x * szerokosc
proj_vert[1].y = proj_vert[1].y * wysokosc + 1
proj_vert[2].x = proj_vert[2].x * szerokosc
proj_vert[2].y = proj_vert[2].y * wysokosc + 1
proj_vert[3].x = proj_vert[3].x * szerokosc
proj_vert[3].y = proj_vert[3].y * wysokosc + 1
paitutils2.drawLine(proj_vert[1].x,proj_vert[1].y,proj_vert[2].x,proj_vert[2].y)
paitutils2.drawLine(proj_vert[1].x,proj_vert[1].y,proj_vert[3].x,proj_vert[3].y)
paitutils2.drawLine(proj_vert[3].x,proj_vert[3].y,proj_vert[2].x,proj_vert[2].y)
term.setTextColor(colors.white)
--term.write("w["..w.."] ")
--newLine()
--term.write(" x[" .. proj_vert[1].x .. "] y[" .. proj_vert[1].y .. "] x2[" .. proj_vert[2].x .. "] y2[" .. proj_vert[2].y .."] \n")
--newLine()
--term.write(" x[" .. proj_vert[1].x .. "] y[" .. proj_vert[1].y .. "] x2[" .. proj_vert[3].x .. "] y2[" .. proj_vert[3].y .."] \n")
--newLine()
--term.write(" x[" .. proj_vert[3].x .. "] y[" .. proj_vert[3].y .. "] x2[" .. proj_vert[2].x .. "] y2[" .. proj_vert[2].y .."] \n")
--newLine()
end
if someone wants to try and replicate the setup it is a 6x8 advanced monitor as a display on the left and advanced computer on the right(it is important the monitor is on the left ).modpack is ftb revelation but it should work with just the computercraft mod instaled.

RoR: Method to return a statement in a json format?

I'm looking for a method that will return this statement in a JSON format.
def statement
total = 0
bonus points = 0
result = 'Car rental for #{#name.to_s}\n'
for r in #rentals
this_amount = 0
case r.car.style
when Car::SUV
this_amount += r.days_rented * 30
when Car::HATCHBACK
this_amount += 15
if r.days_rented > 3
this_amount += (r.days_rented - 3) * 15
end
when Car::SALOON
this_amount += 20
if r.days_rented > 2
this_amount += (r.days_rented - 2) * 15
end
else
end
if this_amount < 0
bonus_points -= 10
end
bonus_points = bonus_points + 1
if r.car.style == Car::SUV && r.days_rented > 1
bonus_points = bonus_points + 1
end
result += r.car.title.to_s + "," + this_amount.to_s + "\n"
total += this_amount
end
result += "Amount owed is " + "#{total.to_s}" + "\n"
result +="Earned bonus points: " + bonus_points.to_s
result
end
What method would I need to add to my class to return this statement in a JSON format? Thank you.
Simplest way to do that
return {:result => result}
at the end of your method.
But if you are using controller to show data to user, I would prefer using .to_json in my controller method

Start second while loop only after first is finished

I'm trying to write a function that puts the remaining seconds into a human readable format. The problem I'm having(I think) is that my second while loop is trying to do it's job before the first is finished. I'll end up with "1 hour, 271 minutes and 37 seconds. In my latest attempt, I tried to use minNeeded but that doesn't work either because it's checking for it's existence prior to the first loop being finished. How can I manage this?
function prettyTime(secs)
local hr = 0
local hrDisplay = ''
local min = 0
local minDislplay = ''
local minNeeded = 0
if(secs >= 3600) then
while secs >= 3600 do
secs = secs - 3600
hr = hr + 1
if secs < 3600 then
secsRemaining = secs
minNeeded = 1
end
end
else
minNeeded = 1
end
while true do
if(minNeeded == 1){
while secsRemaining >= 60 do
secsRemaining = secsRemaining - 60
min = min + 1
end
end
end
if hr > 1 then
hrDisplay = hr .. ' hours, '
elseif hr == 1 then
hrDisplay = '1 hour, '
end
if min > 1 then
minDisplay = min .. ' minutes and '
elseif min == 1 then
minDisplay = '1 minute and '
else
minDisplay = ''
end
return hrDisplay .. minDisplay .. secs .. ' seconds'
end
your Code has few bugs, if(minNeeded == 1){ is syntax error, while true do will never break.
Here is the simple converter,
function prettyTime(sec)
local sec = tonumber(sec)
if sec <= 0 then
return "00.00.00";
else
h = tonumber(string.format("%02.f", math.floor(sec/3600)))
m = tonumber(string.format("%02.f", math.floor(sec/60 - (h*60))))
s = tonumber(string.format("%02.f", math.floor(sec - h*3600 - m*60)))
-- return h.."."..m.."."..s
end
local res = ''
if h == 1 then
res = res ..h .. ' hour, '
elseif h > 1 then
res = res ..h .. ' hours, '
end
if m <= 1 then
res = res ..m .. ' minute, '
elseif m > 1 then
res = res ..m .. ' minute, '
end
if s <= 1 then
res = res ..s .. ' second, '
elseif s > 1 then
res = res ..s .. ' seconds '
end
return res
end
print(prettyTime(3670)) -- 1 hour, 1 minute, 10 seconds

Checkerboard challenge

I'm close to solving this challenge, however, I cannot figure out how to refactor my code to get the following spec to pass.
Spec to pass:
Test.assert_equals(checkered_board(2), "\u25A1 \u25A0\n\u25A0 \u25A1")
My error:
Expected: "\u25A1 \u25A0\n\u25A0 \u25A1", instead got: "\u25A1 \u25A0 \n\u25A0 \u25A1 "
My attempt (via visual on repl.it, everything appears correct)
def checkered_board(dimension)
return false unless dimension.integer? && dimension >= 2
checkboard = nil
checker_array = []
count = dimension
while dimension % 2 == 0 && count > 0 # set-up for even number passed in
if count % 2 == 0
checkboard = ("\u25A1 \u25A0 ") * (dimension / 2)
checkboard += "\n"
checker_array << checkboard
count -= 1
else
checkboard = ("\u25A0 \u25A1 ") * (dimension / 2)
if count == 1 #if count is the last number before 0, do not add \n to pass spec
checker_array << checkboard
else
checkboard += "\n"
checker_array << checkboard
end
count -= 1
end
end
while dimension % 2 == 1 && count > 0 # set-up for odd number passed in
if count % 2 == 1
checkboard = ("\u25A0 \u25A1 ") * (dimension / 2)
checkboard += "\u25A0"
if count == 1 #if count is the last number before 0, do not add \n to pass spec
checker_array << checkboard
else
checkboard += "\n"
checker_array << checkboard
end
count -= 1
else
checkboard = ("\u25A1 \u25A0 ") * (dimension / 2)
checkboard += "\u25A1"
checkboard += "\n"
checker_array << checkboard
count -= 1
end
end
checkboard = checker_array.join("")
checkboard
end
What should I add/do to pass how the \n is within the required passing spec?
Thanks
Figured out my own problem and solution is commented in code below
def checkered_board(dimension)
return false unless dimension.is_a?(Integer) && dimension >= 2
checkboard = nil
checker_array = []
spacer = " "
count = dimension
while dimension % 2 == 0 && count > 0 # set-up for even number passed in
if count % 2 == 0
checkboard = ("\u25A1#{spacer}\u25A0#{spacer}") * (dimension / 2)
checkboard = checkboard[0..-2] + "\n" #solution was here
checker_array << checkboard
count -= 1
else
checkboard = ("\u25A0#{spacer}\u25A1#{spacer}") * (dimension / 2)
if count == 1 #if count is the last number before 0, do not add \n to pass spec
checker_array << checkboard[0..-2] #solution was here
else
checkboard = checkboard[0..-2] + "\n" #solution was here
checker_array << checkboard
end
count -= 1
end
end
while dimension % 2 == 1 && count > 0 # set-up for odd number passed in
if count % 2 == 1
checkboard = ("\u25A0#{spacer}\u25A1#{spacer}") * (dimension / 2)
checkboard += "\u25A0"
if count == 1 #if count is the last number before 0, do not add \n to pass spec
checker_array << checkboard[0..-1] #solution was here
else
checkboard += "\n"
checker_array << checkboard
end
count -= 1
else
checkboard = ("\u25A1#{spacer}\u25A0#{spacer}") * (dimension / 2)
checkboard += "\u25A1"
checkboard = checkboard[0..-1] + "\n" #solution was here
checker_array << checkboard
count -= 1
end
end
checkboard = checker_array.join("")
checkboard
end

grep logs for the last X minutes every X minutes

I want to grep logs for the last X minutes every X minutes(ex: grep logs of last 5 min every 5 min) without grep-ing anything older. What could be the simplest way to do this?
A Ruby 1.9.3 solution
The second part that you require, I haven't tested it yet :(
Note: Also if you know the location of 'ruby' change the shebang (first line of the script),
for security reasons.
#! /usr/bin/env ruby
require 'date'
require 'pathname'
if ARGV.length != 4
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
exit 1
end
begin
total_amount = Integer ARGV[1]
rescue ArgumentError
$stderr.print "error: parameter 'time' must be an Integer\n"
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end
if ARGV[0] == "-m"
gap = Rational(60, 86400)
time_str = "%b %d %H:%M"
until_next_search = total_amount * 60
elsif ARGV[0] == "-s"
gap = Rational(1, 86400)
time_str = "%b %d %H:%M:%S"
until_next_search = total_amount
elsif ARGV[0] == "-h"
gap = Rational(3600, 86400)
time_str = "%b %d %H"
until_next_search = total_amount * 3600
elsif ARGV[0] == "-d"
time_str = "%b %d"
gap = 1
until_next_search = total_amount * 86400
else
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
exit 1
end
pn = Pathname.new(ARGV[3])
if pn.exist?
log = (pn.directory?) ? ARGV[3] + "/*" : ARGV[3]
else
$stderr.print "error: file '" << ARGV[3] << "' does not exist\n"
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end
search_str = ARGV[2]
now = DateTime.now
while true
total_amount.times do
now -= gap
system "cat " << log << " | grep '" << now.strftime(time_str) << ".*" << search_str << "'"
end
sleep until_next_search
end

Resources