Procese archivos de vídeo de forma recursiva para hacer espacio

Procese archivos de vídeo de forma recursiva para hacer espacio

He maximizado el espacio de almacenamiento que tengo y me gustaría hacer algo de espacio.

He pensado en convertir todos los archivos a mkv y reducir los archivos de alta resolución a una resolución más baja.

Entonces, para convertir mp4 a mkv hay

ffmpeg -i input.mp4 -vcodec copy -acodec copy output.mkv

Y para reducir la escala hay

ffmpeg -i input.mp4 -vf scale=$w:$h <encoding-parameters> output.mp4

pero necesito convertir todos los archivos, no uno solo mp4, necesito eliminar el archivo de entrada después de terminar de procesarlo y tengo que hacer esto solo para archivos por encima de una resolución determinada. También me gustaría mantener la relación de aspecto y no sé si esto lo logra.

Hay una herramienta llamadavideo-dietaeso hace parte de esto.

Esto es lo que me gustaría hacer

Recursively find every file under the current directory
If the file resolution has a height equal or greater to a given height.
  Convert the file to mkv if it's in another format avi, mp4, flv, etc
  Downscale to a lower resolution height, keeping the aspect ratio.

Tal vez yo también deberíabajar la velocidad de fotogramasa 24 fps?

Si hay una manera mejor, me gustaría escucharla.

Respuesta1

Aquí tienes un guión para empezar. Probablemente querrás modificar esto para adaptarlo a tus necesidades, agregar opciones a ffmpeg si deseas cambiar la velocidad de fotogramas, etc.

Tenga en cuenta que hay un condicional allí que verifica si el archivo ya es .mkv, pero en realidad no estoy haciendo nada diferente con ellos, por lo que el condicional no tiene sentido. Simplemente está ahí porque tu pregunta hizo que pareciera que querías hacer algo diferente con ellos, aunque no estoy seguro de por qué. FFMPEG puede escalar y convertir al mismo tiempo.

Pero si desea hacer algo diferente, cambie la línea ffmpeg para cuando el condicional sea verdadero por algo diferente.

#!/bin/bash

# set the resolution above which you want to downscale
maxwidth=1920
maxheight=1080

# set the resolution to downscale to; the width will be
# calculated to preserve aspect ratio
targetwidth=1280

# a counter for errors
errors=0

# recursively find video files; add their names to
# an array to process
mapfile -t filenames < <(find $(pwd) -type f -iregex '.*avi$\|.*mp4$\|.*m4v$\|.*flv\|.*mkv\|.*ogv\|.*webm$\|.*mov')

# loop through the array
for filename in "${filenames[@]}" ; do
    # get the resolution with ffprobe
    res="$(ffprobe -hide_banner -v error -select_streams v:0 -show_entries stream=width,height -print_format csv "$filename")"
    # strip "stream" off "res"
    res="${res#stream,}"
    # parse into width and height
    width="${res%,*}"
    height="${res#*,}"
    # compare to maxwidth/height to see if it should be
    # processed
    if [[ "$width" -ge "$maxwidth" ]] || [[ "$height" -ge "$maxheight" ]] ; then
        # determine the output name
        outputname="${filename%.*}-downscaled.mkv"
        # check if output already exists; if so, skip it
        if [[ -e "$outputname" ]] ; then
            continue
        fi
        # calculate targetheight, divide by 2 multiply by 2
        # to ensure it's even
        targetheight="$(( ( ( (targetwidth * height) / width) / 2) * 2 ))"
        # get file extension
        ext="${filename##*.}"
        # do something different with mkvs?
        # not sure why you would though
        if [[ "$ext" =~ '[Mm]{Kk][Vv]' ]] ; then
            ffmpeg -i "$filename" -vf scale="$targetwidth:$targetheight" "$outputname"
            exitcode="$?"
        else
            ffmpeg -i "$filename" -vf scale="$targetwidth:$targetheight" "$outputname"
            exitcode="$?"
        fi
        # if conversion was a success, delete original file
        if [[ "$exitcode" == 0 ]] && [[ -e "$outputname" ]] ; then
            rm "$filename"
        else
            echo
            echo "Error processing $filename" >&2
            echo "Not deleted!"
            let errors++
            echo
        fi
    fi
done

# report number of errors if there were any
if [[ "$errors" == 0 ]] ; then
    exit 0
fi
echo "There were $errors errors!" >&2
exit 1

Puede que sea un poco excesivo y puede que haya formas de simplificarlo, pero eso es lo que yo haría.

información relacionada