'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