如何在检测到分辨率变化时分割视频文件?(即包含多个宽度的记录流)

如何在检测到分辨率变化时分割视频文件?(即包含多个宽度的记录流)

我有许多视频文件(flv/mp4),它们在播放中途改变分辨率(720p/1080p/640)。

我想使用类似 ffmpeg 的东西来自动检测分辨率的变化并将视频分成各自的场景,保持其现有的编码质量:无需重新编码的片段(Video1-scene1.flv,Video1-scene2.flv 等)。

我找到了各种方法来分割静音、场景变化、黑色场景,但没有像改变分辨率宽度这样简单的方法。

这些文件经常导致视频编辑器/修剪器崩溃,如果我只是将整个视频转换为 1080p,手动识别和删除低分辨率场景非常耗时。

该算法可能很简单,只需将当前帧与前一帧进行比较,如果它们的分辨率不同,则分割视频并开始新的片段。

有人可以帮忙吗?

示例文件(temporarily available) 示例.flv

以下是一些相关答案:

使用 FFmpeg 从视频文件中剪切部分从开始位置到结束位置

https://stackoverflow.com/questions/36074224/how-to-split-video-or-audio-by-silent-parts

在黑帧(场景变化)处自动将较大的 .mov 视频文件分割为较小的文件?

通过场景检测使用 FFMPEG 分割视频

其他资源:
使用 Lord Neckbeard 的解决方案,我附上了最终在 Windows10 上运行的(不幸的是,非常手动)过程。也许它可以引发有关 ffmpeg 的其他想法。
(我为任何足够专业的人士发布了一个单独的问题:使这个过程自动化...

将视频拖到包含以下内容的批处理文件中:

ffprobe -v 错误 -show_entries 帧=pkt_pts_time,宽度,高度 -select_streams v -of csv=p=0 %1 > allkeyframes.txt

(allkeyframes.txt 示例...)

13.652000,640,480
13.755000,640,480
13.597000,480,360
13.652000,480,360

将此文本粘贴到 POWERSHELL 中:

$o=""
$n=0
foreach($line in (Get-Content allkeyframes.txt)){
  $nline = $line.Split(",")
  $nline2=($nline[1]+$nline[2])
  if ($nline2 -ne $preventry) {
    $n0=$nline[0]
    $o="$o,$n0"
    $n=$n0
}
  $preventry = $nline2
}
if ($o.length -gt 1){
echo $o.Remove(0,1) > resolutionchanges.txt
} else {
Write-Host "No resolution changes found" -ForegroundColor Red
}

(分辨率变化.txt:)

13.597000,25.618000,33.628000,45.598000

粘贴resolutionchanges.txt的内容并将“input.flv”更改为视频名称后,在命令窗口中输入以下内容(Win10拒绝我对此进行批处理的尝试):

ffmpeg -i 输入.flv -map 0 -c 复制 -segment_times 13.597000,25.618000,33.628000,45.598000 -reset_timestamps 1 -f 片段输出_%03d.flv

答案1

Lazyman 的解决方案是使用缩放过滤器以使每个输入符合所需的宽度 x 高度

对于您提出的解决方案,您可以使用它ffprobe来确定何时发生尺寸变化。

ffprobe -v error -show_entries frame=pkt_pts_time,width,height -select_streams v -of csv=p=0 input.flv

宽度和高度变化期间的示例输出摘录(key_frame、pkt_pts_time、width、height):

0,89.081000,480,640
0,89.281000,480,640
0,89.481000,480,640
1,89.568000,640,480
0,89.592000,640,480
0,89.632000,640,480
1,97.749000,480,640

尺寸变化可能会发生在关键帧上,如果需要流复制,则可以在此处进行剪切。如果您只想要关键帧,请添加该-skip_frame nokey选项。

然后使用段复用器

ffmpeg -i input.flv -map 0 -c copy -segment_times 89.568,97.749 -reset_timestamps 1 -f segment output_%03d.flv

相关内容