sábado, 13 de junio de 2020

Transcodificar vídeos con el móvil

Avisos previos.

Nota: Si no quieres leer paja y quieres ir directo al grano, pasa directo a la parte de "Algo de configuración previa".

Hace mucho tiempo que no publico nada en el blog y creo que ya va siendo hora de compartir algo interesante. En este caso, se trata de una serie de scripts que uso para transcodificar vídeos a x265.

Avisos previos.

Mi idea con esto no es hacer una aplicación, sino compartir algo que hice y que me soluciona un problema en mi vida. No obstante, si alguno tiene dudas sobre lo aquí explicado, no tengo ningún problema en contestarlas por simples que sean.

ToDo y mejoras.

  • Reemplazar el progreso del FFmpeg por una barra de progreso.
  • Respetar la estructura de directorios en el script de transcodificación.

Motivación.

El motivo que me llevó a realizar estos scripts es el de que cada vez que grababa un vídeo con el móvil estos ocupaban muchísimo. Estamos hablado que un vídeo de 2min ocupa del orden de 300MB. Contando con que la memoria interna de mi móvil de gama media se queda en unos 64GB es inaceptable estas cantidades.

Este problema lo achaco a que para poder grabar vídeos de gran calidad, el móvil necesita o bien un procesador muy potente o mucha memoria. Un procesador potente, implicaría un móvil muy caro, además de mucho consumo de batería y mucho calor generado. Por ello supongo que los fabricantes optan por gastar mucha memoria que es más barato y genera menos problemas.

No obstante si post-procesamos estos vídeos podemos reducir el tamaño de estos en aproximadamente un 90%. Esto solo nos repercutirá en un consumo elevado de batería y tiempo, algo que se soluciona dejando el móvil conectado a un cargador por la noche.

Herramientas.

Para realizar este proceso de transcodificación, he usado varias herramientas.

  • FFmpeg:
    Esta es la más importante de todas. Es la que nos permite pasar el vídeo de su codec original a uno de x265.
  • ExifTool:
    Esta la he usado para renombrar los fichero y para preservar en la medida de lo posible las fechas en las que fueron creados los vídeos.
    Esta herramienta está escrita en perl y por tanto será necesario contar con algunas dependencias.
  • Termux:
    Se trata de una potentísima APP que nos permite dotar a nuestro Android de la que quizá sea la mejor consola que podamos usar en este dispositivo.
    Esta APP cuenta con un gestor de paquetes que nos permitirá instalar todo tipo de herramientas del mundo Linux sin necesidad de ser root en el teléfono.

Nota: No es necesario, pero recomiendo por comodidad el teclado Hacker's Keyboard o WiFi Keyboard.

Como funciona.

Los script se dividen en 2.

  • El primero: Nos servirá para transcodificar los vídeos de una carpeta y dejarlos en otra preservando siempre que sea posible la fecha de creación.
  • El segundo: Lo usaremos para extraer la fecha de creación del fichero (la del vídeo original) y renombrarlos a un formato común. Además, borrará el fichero original si se ha especificado.

Forma en la que uso estos scripts:

  1. Uso el primer script para transcodificar toda una carpeta en otra destino.
  2. Visualizo los vídeos con alguna herramienta para ver que están bien.
  3. Uso el segundo script para renombrar las transcodificaciones y borrar los originales.

Algo de configuración previa.

Lo primero de todo será instalar el Termux. Unas pocas lineas más arriba, he dejado el enlace a la web de la aplicación donde hay enlaces tanto al Play como al F-Droid.

Tengo que decir que aunque la aplicación principal es gratuita, la aplicación de los Widget es de pago, pero solo si la instalamos desde el Play.

No es imprescindible, pero más adelante explicaré por qué es buena idea tenerla.

IMPORTANTE: Cada teléfono es un mundo, por lo que todo lo que cuente en esta sección puede variar significativamente según tú modelo.

Una vez instalada, tendremos que concederle permisos al Termux para poder acceder al almacenamiento, que es donde estarán los vídeos de la cámara. Hay dos formas de hacer esto.

Una es ir directamente a los ajustes de tu teléfono y allí en el apartado de aplicaciones buscar el Termux y concederle permisos (no se crean links ni carpeta "storage").

Otra forma más cómoda, es abrir el Termux y ejecutar:

termux-setup-storage

Si Termux no tiene permisos para acceder al almacenamiento, se mostrará una ventana donde tendremos que aceptarlos. Como tarea extra, creará la carpeta ~/storage con distintos links a distintas partes del almacenamiento.

Ahora abrimos el Termux y en la línea de comandos ejecutamos lo siguiente para crear un par de carpetas:

# En esta dejaremos los 2 scripts principales. mkdir scripts # Estas es imprescindible que tenga este nombre si queremos usar Termux Widget. mkdir .shortcuts

Termux cuenta con un repositorio de paquetes del estilo de APT de Debian desde el cual podremos instalar infinidad de herramientas. En nuestro caso solo nos interesan 3 (Enter a todas las preguntas).

apt update apt install ffmpeg exiftool perl

Y ahora instalamos una dependencia de perl necesaria para el ExifTool. Esto irá lanzando preguntas, dejamos todo por defecto (enter, enter, enter....) y listo.

cpan -i Image::ExifTool

Pasar los scripts al móvil

Nota: Con el tiempo puede que lo suba a GitLab, pero de momento esto es lo que hay.

Ahora toca pasar estos scripts a la carpeta previamente creada y darles permisos de ejecución. Existen muchas formas de hacerlo, ADB, usar el WiFi Keyboard, escribirlos a mano, scp, netcat, etc. Yo explicaré una forma.

Se puede abrir este post con el navegador del móvil, copiarlo y después abrimos el Termux y ejecutamos:

# Solo por asegurar que tenemos el editor de ficheros. apt install nano nano -t ~/scripts/transcode.sh

Esto abrirá el editor, pegamos el contenido y presionamos: Ctrl+x

Nota: Si no contamos con la tecla virtual de Ctrl en nuestro teclado, se puede pulsar el botón físico de bajar volumen del teléfono.

Ahora solo queda darle permisos de ejecución:

chmod u+x ~/scripts/transcode.sh

Una vez hecho esto, repetimos estos dos pasos para el script 2 (rename.sh).

Scripts.

Script 1 (transcode.sh).

#!/data/data/com.termux/files/usr/bin/bash # Transcodifica uno o más videos en una carpeta por defecto o específica # preservando el timestap de cada vídeo. # # origen := { video | carpeta_de_videos } # $0 origen [[origen...] carpeta_destino] # # La extensión va definida en la variable $video_ext. # # v1.1 # Autor: McA video_ext="${video_ext:-mp4}" # Default dst folder. [[ -d ${@: -1} ]] || set "$@" ~/storage/dcim/Transcode # Transcodifica un vídeo en otra carpeta. # En la carpeta de destino ($2) se creará un fichero con el código de # error y el nombre del fichero de origen con la ruta canonicalizada. # # transcode <fichero origen> <ruta destino> transcode(){ local ret local dst_file [[ -f $1 ]] || return 1 [[ -d $2 ]] || return 2 dst_file="$2"/"${1##*/}" dst_file="${dst_file%.*}.mkv" # Si existe el fichero. [ -f "$dst_file" ] && return 3 # -progress http://127.0.0.1:8080/automagic/ffmpeg \ ffmpeg \ -y \ -i "$1" \ -c:v libx265 \ -c:a aac \ -b:a 128k \ -map_metadata 0 \ "$dst_file" ret=$? touch -cr "$1" "$dst_file" echo "$?: $1" >> "$2"/done.txt return $ret } dst_folder=$(readlink -f "${@: -1}") [[ -d $dst_folder ]] || exit 2 unset folders files # Pasar los parametros a 2 vectores. # Uno de ficheros y otro de carpetas. for (( i=1; i<$#; i++ )); do tmp=$(readlink -f "${!i}") [[ -f $tmp && $tmp =~ \.$video_ext$ ]] && files+=("$tmp") [[ -d $tmp ]] && folders+=("$tmp") done # Buscar todos los vídeos de cada carpeta y # subcarpeta y pasarlos al vector de ficheros. for i in "${folders[@]}"; do while read f; do files+=("$f") done < <(find "$i" -type f -name "*.$video_ext") done # Transcodificar todos los vídeos encontrados. for i in "${files[@]}"; do transcode "$i" "$dst_folder" || echo "Ocurrio algún error: $?." >&2 done

Script 2 (rename.sh)

#!/data/data/com.termux/files/usr/bin/bash # $0 transcode destino [original] # # Mueve de una carpeta <transcode> o otra <destino> todos los ficheros mkv y jpg # y renombra por fecha. # # Si se especifica una carpeta <original>, se borrarán de esta carpeta todos los # ficheros que coincidan con los ficheros de <transcode> antes de haber sido # renombrada sin tener en cuenta la extensión. # Autor: McA # v1.2 # Notas varias: # Recuperar todas las tags: # exiftool -s -G $fichero # # # Extraer solo el valor de un tag: # exiftool -NombreDelTag -s -s -s $fichero # # # Pasar el tag DateTimeOriginal de UTC a la hora local. # date -d $(exiftool -DateTimeOriginal -s -s -s -d @%s $fichero) +%Y-%m-%d_%H-%M-%S err(){ echo -e "\e[31m[ERROR]:\e[0m $1" >&2 exit $2 } type exiftool &> /dev/null || err "No se pudo encontrar el programa: exiftool" 3 perl -MImage::ExifTool -e 1 &> /dev/null || { # apt install make e="No se encuentra instalado el modulo de perl Image::ExifTool." e+="\n\e[33m[Info]\e[0m: Puedes instalarlo con \e[36m'cpan -i Image::ExifTool'\e[0m" err "$e" 3 } # Extrae la fecha más fiable de entre los tags del vídeo $1. # # NOTA 1: Algunos tags se encuentran en UTC, por lo que la hora recuperada # podría no ser la esperada. Para ello se pasa la hora UTC a la GMT+X según # la configuración del dispositivo. Esta zona puede controlarse mediante la # variable $TZ (TimeZone). Por ejemplo: # export TZ=America/Mexico_City # Para más opciones se puede consultar /usr/share/zoneinfo/**. # # NOTA 2: Esta pensada para ser usada con tags de ficheros Matroska (mkv), pero # puede funcionar igualmente con otros tags. # Para otros tags consultar: https://exiftool.org/TagNames/ get_date(){ local i date for i in DateTimeOriginal CreateDate FileModifyDate; do date=$(exiftool -$i -s -s -s -d %s "$1" 2>/dev/null) [[ $date -gt 0 ]] && break done date -d @$date +%Y-%m-%d_%H-%M-%S } # Añade números al final del nombre del fichero ($1) # hasta que no exista o sea igual a $2 (shasum). unico(){ local nom=${1%.*} local ext=${1##*.} local z=0 local ret=$1 local sha=$(shasum "$2"|sed 's/\( \+\).*/\1/') while [[ -f $ret ]]; do echo "$sha$ret" | shasum -cs && break z=$(($z + 1)) ret=${nom}_$z.$ext done echo -n "$ret" } dir_t="${1%/}" # Transcode. dir_d="${2%/}" # Destino. dir_o="${3%/}" # Original. [[ -d $dir_t ]] || err "No se ha especificado el directorio: transcode" 1 [[ -d $dir_d ]] || err "No se ha especificado el directorio: destino" 2 echo -e "Origen: \e[31m$dir_t\e[0m" echo -e "Destino: \e[32m$dir_d\e[0m" while read i; do echo -n "$i: " old="$dir_t/$i" datef=$(get_date "$old") dst=$(dirname "$i")/$datef.${i##*.} new=$dir_d/$dst new=$(unico "$new" "$old") if [[ -f $new ]]; then echo -e "Ya existe \e[31m$new\e[0m." rm "$old" else echo -e "Moviendo a \e[32m$dst\e[0m." mkdir -p "${new%/*}" mv "$old" "$new" fi [[ $? -eq 0 && -d $dir_o ]] && { rm -f "$dir_o/${i%.*}".* } done < <( \ find "$dir_t" \ -type f \( \ -iname "*.jpg" -o \ -iname "*.jpeg" -o \ -iname "*.mkv" \) \ -printf %P\\n)

Widget de accesos directos (opcional)

Estos scripts son la base para realizar de manera semiautomática la transcodificación de los vídeos, pero resulta mucho más cómodo contar con accesos directos que hagan la tarea con solo un clic sin tener que entrar en la línea de comandos. Para ello será necesario instalar la APP del termux-widget (de pago si se instala desde el play).

Una vez instalada, hay que crear los siguientes scripts. Es importante mencionar que en este ejemplo, se pasarán los vídeos de la carpeta DCIM/Camera a DCIM/Transcode (script 1). Y de DCIM/Transcode a DCIM/Done (script 2). Esto mismo se puede aplicar por ejemplo a los vídeos de Whatsapp.

Script 1 (~/.shortcuts/transcode-Camera.sh)

#!/data/data/com.termux/files/usr/bin/bash # Carpeta intermedia donde quedarán los vídeos a repasar antes de renombrar. mkdir -p ~/storage/dcim/Transcode ~/scripts/transcode.sh ~/storage/dcim/{Camera,Transcode} # Bell x3. for i in 1 2 3; do echo -n $'\007' sleep 0.3 done echo echo -e "\e[1;36m-- \e[1;32m¡Listo! \e[1;36m--\e[0;0m" read -sn1

Script 2 (~/.shortcuts/Rename-Transcode.sh)

#!/data/data/com.termux/files/usr/bin/bash # Carpeta donde quedarán los vídeos una vez renombrados. mkdir -p ~/storage/dcim/Done ~/scripts/rename.sh ~/storage/dcim/{Transcode,Done,Camera} # Bell x3. for i in 1 2 3; do echo -n $'\007' sleep 0.3 done echo echo -e "\e[1;36m-- \e[1;32m¡Listo! \e[1;36m--\e[0;0m" read -sn1

No hay comentarios:

Publicar un comentario