media/multimedia/ FFmpegWrapperScripts


Back to FFmpeg.

I have a few wrapper scripts for things like getting the duration or resolution of a file or files.

getvres – get vertical resolution of video. It is easy to modify this to get the w x h dimensions of a video. While I use Python most of the time, this one is written in good old fashioned Perl. Note that for one file, it just prints out the resolution (no filename), but for more than one it prints the filenames. This is so as to use this as a helper script in other scripts.

#!/usr/bin/perl

@s = ();
%f = ();
$total = 0;
for $file(@ARGV) {
  open(PIPE,"ffprobe '$file' 2>&1 |");
  @a = <PIPE>;
  close PIPE;
  for(@a) {
    if(/Video:.*\s\d{2,}x(\d+)[^\d]/) {
        $x = "$1";
        if( scalar(@ARGV) > 1 ) {
          print "$file: $x\n";
        } else {
          print "$x\n";
        }
        last;
    }
  }
}

getvdurs – get duration of videos

#!/usr/bin/perl

@s = ();
%f = ();
$total = 0;

sub tohms {
  # convert a number of seconds (e.g. 5314) to something
  # in the format 1h28m34s
  my ($t) = @_;
  my ($d,$h,$m,$s);
  $s = $t % 60;
  $m = int($t / 60) % 60;
  $h = int($t / 3600) % 24;
  $d = int($t / (3600*24));
  my ($x);
  $x = "";
  if( $d ) { $x .= "${d}d";}
  if( $h ) { $x .= "${h}h";}
  if( $m ) { $x .= "${m}m";}
  if( $s ) { $x .= "${s}";}
  if( $x =~ /^$/ ) { $x = "0"; }
  return $x;
}

for $file(@ARGV) {
  open(PIPE,"ffprobe '$file' 2>&1 |");
  @a = <PIPE>;
  close PIPE;
  for(@a) {
    if(/Duration:(.*),/) {
      $_ = $1;
:      s/,.*$//;
                        s/\..*//;
      @hms = split /:/;
      $t = 3600*int($hms[0]) + 60*int($hms[1]) + int($hms[2]);
      print "$file: $t ".(tohms($t))."\n";
      $total += $t;
      last;
    }
  }
}

# if more than one file, print a grand total
if((scalar @ARGV) > 1) {
  print "Total: $total ".(tohms($total))."\n";
}

hms – a script to convert from 1h34m2s format to a number of seconds. This is in Python, and if I ever need to rewrite the above Perl scripts, I'll probably write them as Python, though Perl scripts are slightly quicker to launch.

#!/usr/bin/env python3

import sys,re
args = sys.argv[1:]

d = {'s':1,'m':60,'h':60*60,'d':24*60*60}

if len(args) == 0:
    print(0)
else:
    a = args[0]
    if re.match(r"^\d+$",a):
        print(a)
    else:
        if re.match(r"\d",a[-1]):
            a += "s"
        b = list(filter(lambda t: len(t)>0,re.split(r"(\d+[dhms])",a)))
        s = 0
        for x in b:
            if not re.match(r"^\d+[dhms]$",x):
                print("Invalid {} ({})".format(a,x),file=sys.stderr)
            else:
                u = x[-1]
                if not u in d:
                    print("Invalid unit {} ({}})".format(u,x),file=sys.stderr)
                else:
                    s += int(x[:-1])*d[u]
        print(s)

rn-vid This turns a video filename my_video.mp4 into something of the form my_video-720p-35m12s.mp4. The reason was largely that KodiPlayer does not list file durations unless videos are listed by duration – so this puts the duration into the filename. The resolution then allows for multiple versions of the same file to be in the same directory without clashes.

#!/usr/bin/perl

if(@ARGV) {
  @a=@ARGV;
} else {
  @a = <*.mp4>;
}
for $a(@a) {
    if($a =~ m@^(.*)\.mp4$@) {
        # Is it an .mp4 file? (should be!)
        $b = $1;
        $suf = "";
        if( $b =~ m@^(.*)-(\d+p)-([\dhms]+)(_\w+)?$@ ) {
            # Already has res/dur, so strip
            $b = $1;
            $suf = $4;
        }
        $r = `getvres $a`; chomp $r;
        $s = `getvdur $a`; chomp $s;
        $c = "$b-${r}p-$s$suf.mp4";
        if( $a eq $c ) {
            print "# No need to rename: $a\n";
        } else {
            print "mv -vn '$a' '$c'\n";
        }
    }
}