#!/bin/sh ## ## takes three arguments - the .srt filename and a ## ms shift value with possibly negative sign. ## ## if a third argument is given of the form ## 2/1000 ## then it will be taken as a PROGRESSIVE time ## adjustment applied at the rate of, for the ## example, 2 milliseconds later per second, ## effectively speeding up or slowing down the ## subtitle track. ## A progressive option of 0/1000 is considered ## a no-op and can be used as a placeholder if a ## RANGE of lines is specified as a 4th option. ## ## A subrange of entries can be operated on by ## specifying a line range as the fourth option. ## For example: ## ## srtshifter my-subs.srt -5000 0/1000 312-400 ## ## Would cause ONLY lines 312-400 (inclusive) to ## be displayed 5 seconds earlier. ## ## all arguments must use integer values! ## ## I am told that there are people who edit the ## headers of container files to change the frame ## rate, and they are the folks who need to apply ## a speedup or slowdown to account for the slightly ## faster/slower video produced by that heinous ## act. ## ## Note that there is something called "extended srt" ## that looks like this: ## ## 00:00:14,948 --> 00:00:18,247 X1:201 X2:516 Y1:397 Y2:423 ## <font color="#fbff1c">Whose side is time on?</font> ## ## Phil Ehrens <phil@slug.org>
## The next line tells sh to execute the script using tclsh \
exec tclsh "$0" ${1+"$@"}
set file [ lindex $argv 0 ]
set shift [ lindex $argv 1 ]
set progressive [ lindex $argv 2 ]
set range [ lindex $argv 3 ]
if { ! [ string length $progressive ] } {
set progressive 0/1000
}
set rstart 1
set rend 10000
regexp {(\d+)-(\d+)} $range -> rstart rend
set fid [ open $file r ] set data [ read $fid [ file size $file ] ] close $fid set fid [ open $file.out w ]
set time_rx {^(\S+)\s+-->\s+(\S+)$}
proc timestamp { msecs } {
set timeatoms [ list ]
if { [ catch {
foreach div { 3600000 60000 1000 1 } \
mod { 24 60 60 1000 } {
set n [ expr {$msecs / $div} ]
if { $mod > 0 } { set n [ expr {$n % $mod} ] }
if { [ string equal 0 $n ] } { set n 00 }
if { [ string length $n ] == 1 } { set n 0$n }
lappend timeatoms $n
}
set stamp [ join [ lrange $timeatoms 0 2 ] : ]
set ms [ lindex $timeatoms 3 ]
if { [ string length $ms ] == 2 } { set ms 0$ms }
set stamp $stamp,$ms
} err ] } {
return -code error "timestamp: $err"
}
return $stamp
}
proc millify { h m s ms } {
foreach t [ list h m s ms ] f [ list 3600000 60000 1000 1 ] {
if { [ set $t ] } {
set $t [ expr [ string trimleft [ set $t ] 0 ] * $f ]
}
}
set result [ expr { $h + $m + $s + $ms } ]
return $result
}
proc timeshift { shift start end progressive } {
foreach [ list num den ] [ split $progressive / ] { break }
foreach [ list h m s ms ] [ split $start ":," ] { break }
set start [ millify $h $m $s $ms ]
set spshift [ expr { $num * ($start / $den) } ]
set start [ expr {$start + $shift + $spshift} ]
foreach [ list h m s ms ] [ split $end ":," ] { break }
set end [ millify $h $m $s $ms ]
set epshift [ expr { $num * ($end / $den) } ]
set end [ expr {$end + $shift + $epshift} ]
set start [ timestamp $start ]
set end [ timestamp $end ]
set line "$start --> $end"
return $line
}
foreach line [ split $data "\n" ] {
if { [ regexp {^\d+$} $line ] } {
set index $line
}
if { $index >= $rstart && \
$index <= $rend && \
[ regexp -- $time_rx $line -> start end ] } {
set line [ timeshift $shift $start $end $progressive ]
}
puts $fid $line
}
exit
See also ssa2srt
See also srtinterpolate