Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
ffmpeg screen recorder
#!/usr/bin/env perl
use 5.012;
use warnings;
use autodie qw(:default exec);
my %window = get_window_info();
my $metadata = sprintf('-metadata title="screencap of window: %s"', $window{title});
chomp(my $datetime = `date +%F_%a_%H.%M.%S.%N`);
my $output_dir = "$ENV{HOME}/ffrec";
mkdir($output_dir) unless -d $output_dir;
my $output_file = sprintf('%s/%s-%dx%d-%s.mkv',
$output_dir,
$datetime,
@window{qw(width height)},
flatten_filename($window{title}),
);
=pod
Few notes:
* libx264rgb doesn't multithread and the presets range from too much IO to too much CPU
* libvpx with realtime settings can't keep up, so it destroys the quality instead
=cut
# Crude framerate limiting heuristic based on pixel count. 480p gets 60fps, 720p gets 25.
sub framelimit {
my ($w, $h, $base) = @_;
$base //= 60;
return int( (848/$w) * (480/$h) * $base / 5 ) * 5;
}
my @params = (
threads => '-threads 0',
audio_input => '-f pulse -i default',
video_input =>
sprintf('-f x11grab -video_size %dx%d -i :0.0+%d,%d -framerate %d',
@window{qw(width height top left)}, framelimit(@window{qw(width height)}, 60)
),
audio_codec => '-codec:a flac',
#video_codec => '-codec:v libvpx',
#vp8_flags => '-quality realtime -speed 0 -slices 3',
video_codec => '-codec:v libx264rgb -preset ultrafast -tune animation -qp 0',
#video_codec => '-codec:v libx264 -preset ultrafast -tune animation -qmax 25',
#x264_flags =>
# '-x264opts '.flatten_ffmpeg_opts({ 'open-gop' => undef, 'non-deterministic' => undef }),
metadata => $metadata,
output_file => $output_file,
);
my @cmdline;
push @cmdline, qw(schedtool -R -p 1 -e) if -e '/usr/bin/schedtool';
push @cmdline, qw(ionice -c 2 -n 0) if -e '/usr/bin/ionice';
push @cmdline, 'ffmpeg';
my $pid = fork // die 'Fork error';
exit if $pid;
open(STDOUT, q{>}, "$output_dir/ffrec.out");
open(STDERR, q{>}, "$output_dir/ffrec.err");
system('start-pulseaudio-x11');
exec '/bin/sh' => '-c', join(q{ }, @cmdline, @params[grep {$_ % 2} 0..$#params]);
sub get_window_info {
my $cmd_output = `xwininfo`;
my %window = (
top => 'Absolute upper-left X',
left => 'Absolute upper-left Y',
width => 'Width',
height => 'Height',
);
for ( keys %window ) {
($window{$_}) = $cmd_output =~ /\Q$window{$_}\E: \s+ (\d+)/x;
}
($window{title}) = $cmd_output =~ /Window id: 0x\w+ "(.+)"$/m;
return %window;
}
sub flatten_filename {
my $name = shift;
$name =~ tr/[a-zA-Z0-9]/_/cs;
return $name;
}
sub flatten_ffmpeg_opts {
my $opts = shift;
my %strings = @_ || (
key_prefix => q{},
opt_sep => q{:},
kv_sep => q{=},
);
my $ret = '';
while ( my ($k, $v) = each %{$opts} ) {
$ret .= $strings{opt_sep} if $ret;
$ret .= $strings{key_prefix}.$k;
$ret .= $strings{kv_sep}.$v if defined $v;
}
return $ret;
}

Arnold1 commented Nov 6, 2017

could you translate it to python? does it work on osx?

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