'Randomly extract video frames from multiple files
Basically I have a folder with hundreds of video files(*.avi) each one with more or less an hour long. What I would like to achieve is a piece of code that could go through each one of those videos and randomly select two or three frames from each file and then stitch it back together or in alternative save the frames in a folder as jpegs. Initially I thought I could do this using R but quickly I've realised that I would need something else possible working together with R.
Is it possible to call FFMPEG from R to do the task above?
I've trawled the internet looking for things that could help me start but most of what I've found is too specific and really applicable to what I need to do.
Could anyone please help me out or simply point me in the right direction.
Many thanks
Solution 1:[1]
I had a related question here recently, and found it was more straightforward to do this in bash, if you're using a Unix system.
I might get downvoted to oblivion for posting this answer here as it's not related to R, but I hope it helps. Something like this worked for me:
#!/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
Basically, for each .avi in the directory, the number of frames and FPS is calculated. Then, three random frames are extracted as a .jpg using the $RANDOM
function in bash and feeding the random frame into ffmpeg
as a hh:mm:ss
time by dividing RANDOM_FRAME
by FPS
.
You could always do these calculations from inside R with system()
calls if you're not familiar with bash lingo.
Solution 2:[2]
Try this, worked for me in many format.
Written in bash
ofcrs. I just randomised the seconds, minutes and hours independently in a range of duration of video by applying constraints over it and combined it to form a proper timestamp. All you need was a random timestamp in a video duration range.
#!/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
Now you can just pass it through a another loop from another script to grab your frames, or just make a function ?.
#!/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
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Community |
Solution 2 |