This answer was written in 2009. Since 2013 a video format much better than H.264 is widely available, namely H.265 (better in that it compresses more for the same quality, or gives higher quality for the same size). To use it, replace the libx264 codec with libx265, and push the compression lever further by increasing the CRF value — add, say, 4 or 6, since a reasonable range for H.265 may be 24 to 30. Note that lower CRF values correspond to higher bitrates, and hence produce higher quality videos.
ffmpeg -i input.mp4 -vcodec libx265 -crf 28 output.mp4
To see this technique applied using the older H.264 format, see this answer, quoted below for convenience:
Calculate the bitrate you need by dividing your target size (in bits) by the video length (in seconds). For example for a target size of 1 GB (one gigabyte, which is 8 gigabits) and 10 000 seconds of video (2 h 46 min 40 s), use a bitrate of 800 000 bit/s (800 kbit/s):
ffmpeg -i input.mp4 -b 800k output.mp4
Additional options that might be worth considering is setting the Constant Rate Factor, which lowers the average bit rate, but retains better quality. Vary the CRF between around 18 and 24 — the lower, the higher the bitrate.
ffmpeg -i input.mp4 -vcodec libx264 -crf 20 output.mp4
This is very similar to @goldilock's approach but, IMO, simpler and can deal with empty lines in the file and replaces |
with a line break :
#!/usr/bin/env perl
my ($time, $text, $next_time, $next_text);
my ($c,$i)=0;
while (<>) {
## skip bad lines
next unless /^\s*([:\d]+)\s*:(.+)/;
## If this is the first line. I could have used $. but this is
## safer in case the file contains an empty line at the beginning.
if ($c == 0) {
$time=$1;
$text=$2;
$c++;
}
else {
## This is the counter for the subtitle index
$i++;
## Save the current values
$next_time=$1;
$next_text=$2;
## I am assuming that the | should be interpreted
## as a newline, remove this if I'm wrong.
$text=~s/\|/\n/g;
## Print the previous subttitle
print "$i\n$time,100 --> $next_time,000\n$text\n\n";
## Save the current one for the next line
$time=$next_time; $text=$next_text;
}
}
## Print the last subtitle. It will be dislayed for a minute
## 'cause I'm lazy.
$i++;
$time=~/(\d+:)(\d+)(:\d+)/;
my $newtime=$1 . (sprintf "%02d", $2+1) . $3;
print "$i\n$time,100 --> $newtime,000\n$text\n\n";
Save the script as a file and make it executable, then run:
./script.pl subfile > good_subs.srt
The output I get on your sample was:
1
00:00:44,100 --> 00:01:01,000
" Myślę, więc jestem".
Kartezjusz, 1596-1650
2
00:01:01,100 --> 00:01:06,000
Trzynaste Pietro
3
00:01:06,100 --> 00:01:10,000
Podobno niewiedza uszczęśliwia.
4
00:01:10,100 --> 00:01:13,000
Po raz pierwszy w życiu
zgadzam się z tym.
5
00:01:13,100 --> 00:01:15,000
Wolałbym...
6
00:01:15,100 --> 00:01:19,000
nigdy nie odkryć
tej straszliwej prawdy.
7
00:01:19,100 --> 00:02:19,000
Teraz już wiem...
Best Answer
srt-files are based on running-time, so the frame-rate doesn't matter. If a text is supposed to be shown at 0h10m10s to 0h10m15s, then it will be shown then - it doesn't matter if there are 10, 25, 50 or 100 frames video for each second.
However, sometimes the video-files may be slightly edited, so a subtitle-file made to another "version" of the video (eg. a movie), may not line-up perfectly or may drift. But this is not due to frame-rate.
From a srt-file - note the times, eg. from 0h03m22,520s to 0h03m23,873s: