Skip to content

Commit

Permalink
Don't create empty files
Browse files Browse the repository at this point in the history
When we try to create a new key frame for a cut point, we would only
avoid doing that if the cut point position is *exactly* on a key frame.

Due to how things work, sometimes we may have a request to create a cut
point at a point in time in between frames. If this happens to be less
than a frame before a key frame, the result will then be a zero-sized
"recoded" file, which ffmpeg barfs on when we try to concatenate the
files later.

Fix by exiting early if the requested cut point is less than a frame
before a key frame.
  • Loading branch information
yoe committed Feb 2, 2025
1 parent 0266f6b commit 28c018d
Showing 1 changed file with 37 additions and 25 deletions.
62 changes: 37 additions & 25 deletions scripts/sreview-cut
Original file line number Diff line number Diff line change
Expand Up @@ -242,37 +242,49 @@ foreach my $row(@{$talk->avs_video_fragments}) {
$prev_kf = $kf;
}
if($prev_kf != $row->{fragment_start}) {
# The start point does not fall on a keyframe. This
# means we need to create one, otherwise the video does
# not start correctly, and this confuses firefox
# (amongst others).
#
# Handle this using the following algorithm:
# - First, extract the bit from th last key frame
# before our start point to the next key frame after
# our start point, and re-encode it with a forced key
# frame at our start point.
# - Next, extract the bit from our start point to the
# end of the newly encoded video from that video.
# - Copy the rest of the video file from the next key
# frame without re-encoding.
# The start point does not fall on a key frame. Handle
# the situation
my $profile;
if(defined($config->get("input_profile"))) {
$profile = Media::Convert::Asset::ProfileFactory->create($config->get("input_profile"), $input, $config->get("extra_profiles"));
} else {
$profile = $input;
}
my $temp = Media::Convert::Asset->new(url => "$tempdir/kftemp" . $row->{rawid} . ".mkv", %duration_args, reference => $profile);
$temp->fragment_start($prev_kf);
$temp->duration($cur_kf - $prev_kf);
$temp->force_key_frames($row->{fragment_start} - $prev_kf);
Media::Convert::Pipe->new(inputs => [$input], "map" => [Media::Convert::Map->new(input => $input, type => "allcopy")], output => $temp, vcopy => 0, acopy => 1)->run();
my $recode_fragment = Media::Convert::Asset->new(url => $temp->url, %duration_args);
my $add_fragment = Media::Convert::Asset->new(url => "$tempdir/recoded_$target" . $row->{rawid} . ".mkv", %duration_args, fragment_start => $row->{fragment_start} - $prev_kf);
Media::Convert::Pipe->new(inputs => [$recode_fragment], "map" => [Media::Convert::Map->new(input => $recode_fragment, type => "allcopy")], output => $add_fragment, vcopy => 1, acopy => 1)->run();
push @$segments, Media::Convert::Asset->new(url => $add_fragment->url, %duration_args);
$output->fragment_start($cur_kf);
$target_length -= $temp->duration;
my $rate = $profile->video_framerate;
my ($numerator, $denumerator) = split /\//, $rate;
my $frame_length = 1 / ($numerator / $denumerator);
if (($cur_kf - $row->{fragment_start}) <= ($frame_length)) {
# Cut point is less than one frame before the
# next key frame. Move the cut point to the key
# frame.
$row->{fragment_start} = $cur_kf;
} else {
# The start point is reasonably far away from a
# key frame. This means we need to create one,
# otherwise the video does not start correctly,
# and this confuses firefox (amongst others).
#
# Handle this using the following algorithm:
# - First, extract the bit from th last key frame
# before our start point to the next key frame after
# our start point, and re-encode it with a forced key
# frame at our start point.
# - Next, extract the bit from our start point to the
# end of the newly encoded video from that video.
# - Copy the rest of the video file from the next key
# frame without re-encoding.
my $temp = Media::Convert::Asset->new(url => "$tempdir/kftemp" . $row->{rawid} . ".mkv", %duration_args, reference => $profile);
$temp->fragment_start($prev_kf);
$temp->duration($cur_kf - $prev_kf);
$temp->force_key_frames($row->{fragment_start} - $prev_kf);
Media::Convert::Pipe->new(inputs => [$input], "map" => [Media::Convert::Map->new(input => $input, type => "allcopy")], output => $temp, vcopy => 0, acopy => 1)->run();
my $recode_fragment = Media::Convert::Asset->new(url => $temp->url, %duration_args);
my $add_fragment = Media::Convert::Asset->new(url => "$tempdir/recoded_$target" . $row->{rawid} . ".mkv", %duration_args, fragment_start => $row->{fragment_start} - $prev_kf);
Media::Convert::Pipe->new(inputs => [$recode_fragment], "map" => [Media::Convert::Map->new(input => $recode_fragment, type => "allcopy")], output => $add_fragment, vcopy => 1, acopy => 1)->run();
push @$segments, Media::Convert::Asset->new(url => $add_fragment->url, %duration_args);
$output->fragment_start($cur_kf);
$target_length -= $temp->duration;
}
} else {
$output->fragment_start($row->{fragment_start});
}
Expand Down

0 comments on commit 28c018d

Please sign in to comment.