I'm trying to write a bash script for Terminal to compress a series of GoPro .MP4 videos from the SDcard directly into a smaller .MP4s on a local network server. The GoPro saves .MP4s in the 100GOPRO folder on the card. After filming, I will through that folder and manually put .MP4s from each game into subfolders within the 100GOPRO folder, named A1, A2, A3, etc.
Folder structure
/GoPro/DCIM/100GOPRO/
-------/A1/
-----GX01xxx1.mp4
-----GX01xxx2.mp4
-------/A2/
-----GX01xxx3.mp4
-----GX01xxx4.mp4
-----GX01xxx5.mp4
-----GX01xxx6.mp4
...etc
I would like then like to run a script from the 100GOPRO folder that will do these steps:
- Within each subfolder, auto-create a file.txt with the names of the subfolder's .MP4s in the format to concat the files (each line has "file 'GX01xxx3.mp4'")
- Pass that subfolder's file.txt as the input to ffmpeg to reencode and save to a network folder with the name A1.mp4 or A2.mp4
- Repeat for each subfolder and quit.
I'm getting hung up on the dynamic path to the subfolder's file.txt. My code just creates a file.txt in the 100GOPRO folder, and appends all the subfolder contents into that single long combined text file. The output then would create a correct first MP4, but second MP4 contains folder 1 and 2, then 3 contains 1, 2, and 3, etc.
Here's the script I ran:
#!/bin/bash
for f in A*/*.mp4 ; do
echo file \'$f\' >> list.txt ;
done && ffmpeg -f concat -safe 0 -i list.txt /Volume/Server/Videos/A$f.mp4 && rm list.txt
Clearly, failing in how that path for echo to save in the subfolder A*, how to call that subfolder's file.txt as the input for ffmpeg, and how to name the output after the folder.
Thanks for any help you can offer.
CodePudding user response:
Save the file list to a bash array, then loop over that. Tune the ffmpeg
invocation to your liking.
#!/usr/bin/env bash
declare -a files=( $(find A* -type f -name \*.mp4) )
for file in "${files[*]}"; do
ffmpeg -f concat -safe 0 -i "$file" "/Volume/Server/Videos/A${file}.mp4"
done
CodePudding user response:
Try this:
for d in $(find -maxdepth 1 -type d -name 'A*');
do
printf "file '%s'\n" $d/*.mp4 > $d/inputs.txt
ffmpeg -f concat -safe 0 -i $d/inputs.txt /Volume/Server/Videos/${d:2}.mp4
done
Explanation
- The find looks for directories matching
A*
, and limited to subdirectories only 1-level deep - The glob
$d/*.mp4
matches the mp4 files in each subdirectory, and theprintf
formats that into a list - the
ffmpeg
command is as you specified, the output filename uses the directory name, except it trims the first two characters (transforming./A1
->A1
)
CodePudding user response:
You don't need intermediate files for this:
for d in A*; do
printf '%s\n' "$d"/*.mp4 |
ffmpeg -i concatf:/dev/stdin "/Volume/Server/Videos/${d#?}.mp4"
done