Browse Source

* ssa-retime : options refactoring

master
Alex 'AdUser' Z 6 years ago
parent
commit
fd2d7a2372
  1. 135
      bin/ssa-retime

135
bin/ssa-retime

@ -7,6 +7,9 @@ use utf8;
use Getopt::Long; use Getopt::Long;
use Subtitle::Format::SSA; use Subtitle::Format::SSA;
use Subtitle::TimePoint;
my @points;
sub usage { sub usage {
my ($msg) = @_; my ($msg) = @_;
@ -15,9 +18,9 @@ sub usage {
Usage: ssa-retime <mode> [<options>] -i <file> [ -o <file>] Usage: ssa-retime <mode> [<options>] -i <file> [ -o <file>]
Modes are: Modes are:
* framerate Retime whole file from one fps to another. * framerate Recalculate timing for different fps
* points Retime file specifying point(s) & time shift for it. * shift Shift timing in given points
* shift Shift whole file or it's part for given time. * drift Adjust timing of whole file by time points
Common options: Common options:
-h This help. -h This help.
@ -25,83 +28,77 @@ Common options:
-o <file> Output file. Default: write to stdout. -o <file> Output file. Default: write to stdout.
-v Be verbose. -v Be verbose.
Specific options for 'shift' mode:
-S <string> Retime only events with specified style.
This option may be given more than once.
-s <time> Start time of period, that will be changed.
Default: first event.
-e <time> End time of period, that will be changed.
Default: the latest time found in file.
-l <time> Duration of period above. This option require '-s'
You may select either '-o' or '-e' at the same time.
-t <time> Change time for this value.
Specific options for 'framerate' mode: Specific options for 'framerate' mode:
-f <float> Source framerate. Default: 25.0 fps. -f <float> Source framerate. Default: 25.0 fps.
-F <float> Target framerate. -F <float> Target framerate.
Specific options for 'points' mode: Specific options for 'shift' mode:
-m <mode> How to apply shift by points:
* seq -- apply timeshifts one by one to end of file (default)
* rst -- every next point overrides previous
-p <time>/<time> Point of fixup & time shift in it. Option can be
specified more than once. (see man for details)
Both args must be in form [+-][[h:]m:]s[.ms]
Specific options for 'drift' mode:
-p <time>/<time> Point of fixup & time shift in it. Option can be -p <time>/<time> Point of fixup & time shift in it. Option can be
specified more than once. (see man for details) specified more than once. (see man for details)
Both args must be in form of [-][[h:]m:]s[.ms]. Both args must be in form [+-][[h:]m:]s[.ms]
USAGE USAGE
exit 1; exit 1;
} }
sub add_point {
my ($opt, $val) = @_;
my $p = Subtitle::TimePoint->new;
my $err = $p->parse($val);
die "$err\n" if $err;
push @points, $p;
}
########### init ################### ########### init ###################
$| = 1; $| = 1;
unless (@ARGV and $ARGV[0] =~ m{^(framerate|shift|drift)$}oi) {
usage("You should set mode by first arg");
}
my $mode = shift @ARGV; my $mode = shift @ARGV;
my @points; my %opts = ( loglevel => 0, inrate => 25.0, amode => 'seq');
my %opts = ( loglevel => 0, inrate => 25.0 );
#GetOptions("qvhi:o:S:f:F:p:t:s:e:l:", \%opts)
GetOptions( GetOptions(
'h|help' => \&usage, 'h|help' => \&usage,
'v|verbose+' => \$opts{loglevel}, 'v|verbose+' => \$opts{loglevel},
'i|infile=s' => \$opts{infile}, 'i|infile=s' => \$opts{infile},
'o|outfile=s' => \$opts{outfile}, 'o|outfile=s' => \$opts{outfile},
'S|style=s' => \$opts{style}, 'm|amode=s' => \$opts{amode},
's|shiftstart=s'=> \$opts{shiftstart},
'e|shiftend=s' => \$opts{shiftend},
'l|shiftlen=f' => \$opts{shiftlen},
't|shifttime=f' => \$opts{shifttime},
'f|inrate=f' => \$opts{inrate}, 'f|inrate=f' => \$opts{inrate},
'F|outrate=f' => \$opts{outrate}, 'F|outrate=f' => \$opts{outrate},
'p|point' => \@points, 'p|point=s' => \&add_point,
); );
($opts{infile} and -f $opts{infile})
or usage("Input file not exists");
if ($mode eq 'framerate') { if ($mode eq 'framerate') {
$opts{outrate} $opts{outrate}
or usage("You should set at least '-F' option in this mode"); or die "You should set '-F' option in this mode\n";
($opts{inrate} != 0.0 and $opts{outrate} != 0.0) ($opts{inrate} != 0.0 and $opts{outrate} != 0.0)
or usage("Framerate can't be zero"); or die "Framerate can't be zero\n";
} elsif ($mode eq 'shift') { } elsif ($mode eq 'shift') {
$opts{shifttime}
or usage("You should set '-t' option in this mode");
(not $opts{shiftstart} or $opts{shiftstart} > 0.0)
or usage("Shift start must be positive time");
(not $opts{shiftend} or $opts{shiftend} > 0.0)
or usage("Shift end must be positive time");
(not $opts{shiftlen} or $opts{shiftlen} > 0.0)
or usage("Shift length must be positive time");
} elsif ($mode eq 'points') {
scalar(@points) scalar(@points)
or usage("You should specify at least one shift point"); or die "You should specify at least one timepoint\n";
foreach my $point (@points) { ($opts{amode} eq 'seq' or $opts{amode} eq 'rst')
... or die "Value of -m option should be 'seq' or 'rst'\n";
} } elsif ($mode eq 'drift') {
scalar(@points)
or die "You should specify at least one timepoint\n";
} else { } else {
usage("Incorrect mode: $mode (see help below)"); usage();
} }
$opts{infile}
or die "No input file\n";
my $ssa = Subtitle::Format::SSA->new(debug => !!$opts{loglevel}); my $ssa = Subtitle::Format::SSA->new(debug => !!$opts{loglevel});
unless ($ssa->from_file($opts{infile})) { unless ($ssa->from_file($opts{infile})) {
foreach my $line (@{ $ssa->{log} }) { foreach my $line (@{ $ssa->{log} }) {
@ -110,25 +107,45 @@ unless ($ssa->from_file($opts{infile})) {
exit 1; exit 1;
} }
if (@points) {
@points = sort { $a->time <=> $b->time } @points;
}
if ($mode eq 'framerate') { if ($mode eq 'framerate') {
my $mod = $opts{inrate} / $opts{outrate}; my $mod = $opts{inrate} / $opts{outrate};
foreach my $event (@{ $ssa->{events} }) { foreach my $e (@{ $ssa->events }) {
$event->{start} *= $mod; $e->t_start($e->t_start * $mod);
$event->{end} *= $mod; $e->t_start($e->t_end * $mod);
} }
} elsif ($mode eq 'shift') { } elsif ($mode eq 'shift') {
my $style = $opts{style}; if ($opts{amode} eq 'seq') {
my $start = $opts{shiftstart} // 0.0; while (my $p = shift @points) {
my $end = $opts{shiftend} // (($opts{shiftlen}) ? $start + $opts{shiftend} : undef); foreach my $e (@{ $ssa->events }) {
my $mod = $opts{shifttime}; next if $p->time > $e->t_start;
foreach my $event (@{ $ssa->{events} }) { $e->t_start($e->t_start + $p->shift);
next if ($style and $event->{style} ne $style); $e->t_end ($e->t_end + $p->shift);
next if ($start and $event->{start} < $start); } # foreach
next if ($end and $event->{end} > $end); } # while
$event->{start} += $mod; } elsif ($opts{amode} eq 'rst') {
$event->{end} += $mod; while (my $p = shift @points) {
# use time of next point as upper limit for current
my $end = @points ? $points[0]->time : 0;
foreach my $e (@{ $ssa->events }) {
next if $p->time > $e->t_start; # too early
next if $end and $end <= $e->t_start; # too late
$e->t_start($e->t_start + $p->shift);
$e->t_end ($e->t_end + $p->shift);
} # foreach
} # while
}
} elsif ($mode eq 'drift') {
if ($points[0]->time >= 0.2) {
# add starting point
my $p = Subtitle::TimePoint->new;
$p->parse('0/0');
unshift @points, $p;
} }
} elsif ($mode eq 'points') { # add endpoint
...; ...;
} }

Loading…
Cancel
Save