从多个文件中随机提取视频帧

4
基本上我有一个文件夹,里面有成百上千个视频文件(*.avi),每个文件大约一个小时左右。我想实现的是一段代码,可以遍历这些视频文件,并从每个文件中随机选择两到三个帧,然后将它们拼合在一起,或者将这些帧保存为jpeg格式放入一个文件夹中。 最初我认为可以使用R来完成这项工作,但很快意识到需要与R配合使用其他工具。 是否可以从R中调用FFMPEG执行上述任务? 我已经在互联网上搜寻了很多东西,但大多数都过于具体,并不适用于我的需求。 请问有谁能帮助我或简单地指引我正确的方向呢? 非常感谢。

一个示例命令是:ffmpeg -ss 00:03:24 -i input -frames:v 1 -qscale:v 2 output.jpg。您可以在FFprobe技巧中查看输入持续时间。如何编写脚本取决于您自己。 - llogan
2个回答

3
我最近有一个相关的问题在这里,如果你使用的是Unix系统,我发现在bash中做这个更加简单明了。
我可能会因为在这里发布与R无关的答案而被投票贬低,但我希望它能够有所帮助。以下类似的命令对我有效:
#!/bin/bash

for i in *.avi

    do TOTAL_FRAMES=$(ffmpeg -i $i -vcodec copy -acodec copy -f null /dev/null 2>&1 | grep frame | cut -d ' ' -f 1 | sed s/frame=//)

    FPS=ffmpeg -i 18_1*avi -vcodec copy -acodec copy -f null /dev/null 2>&1 | grep fps | cut -d ' ' -f 2 | sed s/fps=//

    for j in {1..3}

        do RANDOM_FRAME=$[RANDOM % TOTAL_FRAMES]

        TIME=$((RANDOM_FRAME/FPS))

        ffmpeg -ss $TIME -i $i -frames:v 1 ${i}_${j}.jpg

    done

done

基本上,对于目录中的每个 .avi 文件,计算其帧数和 FPS。然后,使用 bash 中的 $RANDOM 函数提取三个随机帧作为 .jpg,并将随机帧通过将 RANDOM_FRAME 除以 FPS 转换成 hh:mm:ss 时间格式,输入到 ffmpeg 中。
如果您不熟悉 bash 术语,可以始终使用 system() 调用从 R 内部执行这些计算。

我认为通过指定帧列表并使用“-vf $FRAMES -vsync 0 -frame_pts 1”提取它们会更快。 - Ketil Malde
使用ffprobe来计算帧率应该更快。例如,ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 $i(https://dev59.com/53I-5IYBdhLWcg3wF0Qc#28376817) - Antti Rytsölä

1

尝试这个方法,我在多个格式中都试过并成功了。 这段代码是用bash编写的。我分别随机设置了秒、分和小时,同时应用时长约束条件,将它们组合成一个适当的时间戳。你只需要在视频播放时间范围内获得一个随机时间戳即可。

#!/bin/bash
##This script will create timestamps.

NO_OF_FRAMES=10
DURATION=$(ffprobe -select_streams v -show_streams input.avi 2>/dev/null | grep DURATION | sed -e 's/TAG\:DURATION=//')
HOUR=$(echo $DURATION | cut -d ':' -f 1)
MIN=$(echo $DURATION | cut -d ':' -f 2)
SEC=$(echo $DURATION | cut -d ':' -f 3 | cut -d '.' -f 1)
  for s in $(shuf -i 0-$SEC -n$NO_OF_FRAMES)
  do
    m=$(shuf -i 0-$MIN -n1)
    h=$(shuf -i 0-$HOUR -n1)
    time=$(echo $h:$m:$s)   
    echo $time
  done

现在你可以通过另一个脚本中的循环来传递它,以获取你的帧,或者只需创建一个函数。
#!/bin/bash
time=$(bash time_stamps.sh | sort)
   for TIME in $time
   do
        ffmpeg -ss $TIME -i input.avi -frames:v 1 sample_$TIME.jpg
   done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接