Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: key frame extraction (DEV-1513) #2300

Merged
merged 1 commit into from Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docker-compose.yml
Expand Up @@ -33,6 +33,7 @@ services:
- ${LOCAL_HOME}/sipi/config:/sipi/config:delegated
- ${LOCAL_HOME}/sipi/images:/sipi/images:delegated
- ${LOCAL_HOME}/sipi/server:/sipi/server:delegated
- ${LOCAL_HOME}/sipi/scripts:/sipi/scripts:delegated
networks:
- knora-net
environment:
Expand Down
182 changes: 81 additions & 101 deletions sipi/scripts/export-moving-image-frames.sh
Expand Up @@ -7,98 +7,75 @@
# - max. 36 frames per matrix
# - one matrix file corresponds to 6 minutes of film

set -e

dir=$(pwd)
sep='---------------------------------'
if [ "${DEBUG:false}" == true ]; then
set -ex
else
set -e
fi

die() {
echo >&2 "$@"
exit 1
function printSeparator() {
echo "---------------------------------"
}

usage() {
echo "usage: <command> -i [infile]>"
echo ${sep}
echo "-i = Inpute file"
echo ${sep}
function die() {
echo >&2 "$@"
exit 1
}

collect() {
film=''
cnt=1
#for b in `ls`; do
for file in *.$1; do
[ -f ${file} ]
name=$2

for c in ${cnt}; do
if [ "$film" == '' ] || [ "$film" == 'VIDEO_TS.VOB' ]; then
film=${file}
else
case $3 in
true) film="$film|$file" ;;
esac
fi
done
cnt=$(expr ${cnt} + 1)
done
needle="|"
num=$(grep -o "$needle" <<<"$film" | wc -l)
num=$(expr ${num} + 1)
function usage() {
echo "usage: <command> -i [infile]>"
printSeparator
echo "-i = Inpute file"
printSeparator
}

# default variables
# current directory
dir=$(pwd)
# name of the input file for which the keyframes should be extracted
infile=''

# alternative to get some information from the source file:
# ffprobe -v quiet -print_format json -show_format -show_streams ~/sourceFile.mov

while getopts ':i:' OPTION; do
case ${OPTION} in
i) infile=$OPTARG ;;
*) echo 'Unknown Parameter' ;;
esac
case ${OPTION} in
i) infile=$OPTARG ;;
*) echo 'Unknown Parameter' ;;
esac
done

if [ $# -eq 0 ]; then
usage
die ''
usage
die ''
fi

# check the arguments: if they exist
num='^[0-9]+$'

# infile must be given and has to be an mp4
# infile must be given and has to be an mp4 by checking if mime-type is video/mp4
if [ -z "${infile}" ]; then
# must be given
usage
die "ERROR: The Input File (-i) is missing"
# must be given
usage
die "ERROR: The Input File (-i) is missing"
fi

# check if mime-type is video/mp4
if file -b --mime-type "${infile}" -ne "video/mp4"; then
die "ERROR: The Input File (-i) is not mp4"
if [ "$(file -b --mime-type "${infile}")" != "video/mp4" ]; then
die "ERROR: The Input File (-i) is not mp4"
fi

# get the right output path, the file and the filename (without extension)
dir=$(dirname "${infile}")
file=$(basename "${infile}")
name="${file%.*}"

cd $dir
cd "${dir}"

# --
# store the frames and matrix files in specific folder;
# folder has same unique name as the uploaded file
mkdir -p $name
cd $name
mkdir -p "${name}"
cd "${name}"

# --
# read frame rate from input file
framerate=$(ffprobe -v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=r_frame_rate ../"${file}")
frame_rate=$(ffprobe -v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=r_frame_rate ../"${file}")

IFS="/" read -a array <<<"$framerate"
IFS="/" read -ra array <<<"$frame_rate"
numerator="${array[0]}"
denumerator="${array[1]}"

Expand All @@ -110,35 +87,35 @@ aspect=$(ffprobe -v error -select_streams v:0 -show_entries stream=display_aspec

# if aspect ratio does not exist in video file metadata
if [ ! -z {$aspect} ]; then
# get aspect ratio from video dimension (width and height)
aspectW=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of csv=s=x:p=0 ../"${file}")
aspectH=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=s=x:p=0 ../"${file}")
else
IFS=':' read -a array <<<"$aspect"
aspectW="${array[0]}"
aspectH="${array[1]}"
# get aspect ratio from video dimension (width and height)
aspectW=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of csv=s=x:p=0 ../"${file}")
aspectH=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=s=x:p=0 ../"${file}")
else
IFS=':' read -a array <<<"$aspect"
aspectW="${array[0]}"
aspectH="${array[1]}"
fi

# --
# framesize
# calculate frame width, height and size
framewidth='256'
frameheight=$(($framewidth * $aspectH / $aspectW))
framesize=${framewidth}'x'${frameheight}

echo ${sep}
# --
printSeparator
echo 'Start with frame export'
# check the outpath for the frames;
# if exists, delete it and create new
if [ -d "frames" ]; then
rm -rf ./frames
rm -rf ./frames
fi
mkdir -p 'frames'

framestart=$(echo ${start} + 1 | bc)
ffmpeg -i ../${file} -an -ss 1 -f image2 -s ${framesize} -vf framestep=${fps} frames/${name}'_f_%d.jpg' 2>&1
ffmpeg -i ../"${file}" -an -ss 0 -f image2 -s ${framesize} -vf framestep="${fps}" frames/"${name}"'_f_%d.jpg' 2>&1

echo 'Done'
echo ${sep}
printSeparator

# --
# create the matrix files
Expand All @@ -147,15 +124,14 @@ echo 'Start with creating matrix file'
# change directory frames
cd frames
# Get the number of files: one image = one second of movie
# numfiles is equivalent to the movie duration (in seconds)
numfiles=(*)
numfiles=${#numfiles[@]}
# number_of_frame_files is equivalent to the movie duration (in seconds)
readonly number_of_frame_files=$(find . -type f | wc -l)

image="${name}_f_1.jpg"

# check if file exists
if [[ ! -f "${image}" ]]; then
die "File not found: ${image}"
die "File not found: ${image}"
fi

# grab the identify string, make sure it succeeded
Expand All @@ -179,38 +155,42 @@ frame_height=$(echo "scale=0; ${matrix_height}/6" | bc)
frame_size="${frame_width}x${frame_height}"
# get every 10th image; start with the image number 5;
# how many matrixes will it produce?
calcmatrix=$(echo "scale=4; (${numfiles}/10)/36" | bc)
calcmatrix=$(echo "scale=4; (${number_of_frame_files}/10)/36" | bc)
# Round the exact fraction to the to the next highest integer
# for the number of matrix files to create 'nummatrix'
readonly interim=$(echo "${calcmatrix}+1"|bc)
readonly nummatrix=${interim%.*}

echo '#Matrix (calculated) '${calcmatrix}
nummatrix=$(echo ${calcmatrix} | awk '{printf("%.0f\n",$1 + 0.75)}')
echo '#Matrix (rounded) '${nummatrix}

t=0
while [ ${t} -lt ${nummatrix} ]; do
echo 'Matrix nr '${t}
firstframe=$(echo "scale=0; ${t}*360+5" | bc)
MATRIX=$(find *_${firstframe}.jpg)' '

c=1
while [ ${c} -lt 36 ]; do
sec=$(echo "scale=0; ${firstframe}+(${c}*10)" | bc)
if [ $sec -lt $numfiles ]; then
img="${name}_f_${sec}.jpg"
if [ -f ${img} ]; then
MATRIX+=${img}' '
fi
fi

let c=c+1
done

# here we make the montage of every matrix file
# montage -size 320x180 DB_4_5.jpg DB_4_15.jpg DB_4_25.jpg DB_4_35.jpg -geometry +0+0 montage1.jpg
# $(echo "montage -size ${matrix_size} ${MATRIX} -tile 6x6 -geometry +0+0 -resize ${frame_size} ../matrix/${name}'_m_'${t}'.jpg'")
montage -size ${matrix_size} ${MATRIX} -tile 6x6 -geometry +0+0 -resize ${frame_size} ../${name}'_m_'${t}'.jpg' 2>&1

let t=t+1
echo 'Matrix nr '${t}
firstframe=$(echo "scale=0; ${t}*360+1" | bc)
MATRIX=$(find *_${firstframe}.jpg)' '

c=1
while [ ${c} -lt 36 ]; do
sec=$(echo "scale=0; ${firstframe}+(${c}*10)" | bc)
if [ $sec -lt $number_of_frame_files ]; then
img="${name}_f_${sec}.jpg"
if [ -f ${img} ]; then
MATRIX+=${img}' '
fi
fi

let c=c+1
done

# here we make the montage of every matrix file
# montage -size 320x180 DB_4_5.jpg DB_4_15.jpg DB_4_25.jpg DB_4_35.jpg -geometry +0+0 montage1.jpg
# $(echo "montage -size ${matrix_size} ${MATRIX} -tile 6x6 -geometry +0+0 -resize ${frame_size} ../matrix/${name}'_m_'${t}'.jpg'")
montage -size ${matrix_size} ${MATRIX} -tile 6x6 -geometry +0+0 -resize ${frame_size} ../${name}'_m_'${t}'.jpg' 2>&1

let t=t+1

done

echo 'Done'
echo ${sep}
printSeparator