cc
A tiny Windows Batch script used for the concatenation of media files. It requires the following software to be properly set up in %PATH% (here in my case is C:\):
To use this script, you’ll have to ensure that the media files you want to concatenate can be concatenated. This means that the files to be concatenated must use the same codec, and when it comes to video files, it also needs them to be in the same framerate, same resolution, and same pixel format; and for audio files, the same sample rate and bit depth is required and, obviously, you cannot concatenate a stereo track to a mono one.
With this being said, ffmpeg also requires the names of the files to be concatenated to be written in a text file in the format of the example shown below:
file 'file 1.ext'
file 'file 2.ext'
file 'file 3.ext'
…
The script can automatically generate a filelist and use that filelist to concatenate media files if the files to be concatenated are put into one folder. The files to be concatenated shall be named orderly, and in the command line environment, a ‘file 10.ext’ won’t come after ‘file 9.ext’ but ‘file 1.ext’. Therefore, if the number of files to be concatenated is greater than 9, then the sequential numbers of those less than 10 shall be added with a ‘0’ ahead of their sequential numbers; and if the number of the files is greater than 99, then a ‘00’ shall be added to those whose sequential numbers less than 10 and a ‘0’ to those less than 100.
With all of the above being said, let’s say, for example, you have the following files to be concatenated put into one folder:
video clip 1.mp4 video clip 2.mp4 video clip 3.mp4 video clip 4.mp4 video clip 5.mp4
And you have checked and you are sure that these video files are using the same codecs both for their video tracks and their audio tracks (and subtitles tracks if existed—and yes, mp4 container does support soft subtitles, it’s just that the format it uses is very rare)—their video tracks are in the same framerate, same pixel format, same resolution, and their audio tracks are in the same sample rate, same bit depth, and same channel setting.
Now, you can open a command window at that very location and use
cc *.mp4 "final video.mp4"
to concatenate these five video clips into one file with the name ‘final video.mp4’.
By default, the concatenation process will automatically strip off and discard any metadata that existed in the original files. If this is not desired, you can use switch -n to tell the script not to do so. But I assume ffmpeg will only take the metadata from the first file and use them as the metadata for the final output.
If switch -l is applied, then the script will only output a text file with the desired final output name, in which all the files matching the criteria given are listed in the format that ffmpeg accepts. For example, if you use
cc "Boreas *.mp4" "final video.mkv" -l
Then the script will only list all the files whose filename starts with ‘Boreas ’ to a text file named ‘final video.mkv.txt’; no actual concatenation is processed.
This would be very useful when you have video clips made from Boreas, Zephyrus, Notus, and Eurus, but you only want to concatenate clips from the first three into the final video and leave the clips made by Eurus behind. In this case, you’ll need to manually type the command three times in the order as follows:
cc "Boreas *.mp4" "final video.mkv" -l
cc "Zephyrus *.mp4" "final video.mkv" -l
cc "Notus *.mp4" "final video.mkv" -l
So let’s say Boreas has made three video clips, while Zephyrus made four and Notus made two, then the final ‘final video.mkv.txt’ shall look like something as follows (suppose they all have their own naming patterns), with videos from Eurus, ‘EURUS HAVE A LOOK AT MY AWESOME VIDEO.mp4’, not included:
file 'Boreas 1.mp4'
file 'Boreas 2.mp4'
file 'Boreas 3.mp4'
file 'Zephyrus V01.mp4'
file 'Zephyrus V02.mp4'
file 'Zephyrus V03.mp4'
file 'Notus video part A.mp4'
file 'Notus video part B.mp4'
Now all you need is to use the switch -m to order the script to concatenate files from an already written filelist text file, which can be done by the example command shown below:
cc -m "final video.mkv.txt"
And now you’ll have a video file with the name ‘final video.mkv’, containing all the video clips made from Boreas, Zephyrus, and Notus in the order you want, with the filelist file ‘final video.mkv.txt’ now mysteriously disappeared. If, for whatever reason that you would like to see the filelist file to be kept, just pass -k to the script to do the trick.
It seems like that I have, by giving these examples, put the switches at some specific positions; and yet in fact, the positions of the switches are totally irrelevant.
The batch
@echo off
chcp 65001 >nul
setlocal enabledelayedexpansion
set "e="
set "f="
set "k="
set "l="
set "m="
set "n="
set "o="
set "t="
:a
if /i "%~1"=="" goto p
if /i "%~1"=="-l" set "l=1"
if /i "%~1"=="-m" set "m=1"
if /i "%~1"=="-k" set "k=1"
if /i "%~1"=="-n" set "n=1"
if /i not "%~1"=="-l" if /i not "%~1"=="-m" if /i not "%~1"=="-k" if /i not "%~1"=="-n" (
if not defined t (set "t=%~1") else if not defined f (set "f=%~1")
)
shift
goto a
:p
if /i "%l%"=="1" (
if not defined t if not defined f goto e
for %%a in (%t%) do echo file '%%a'>>"%f%.txt"
goto e
)
if /i "%m%"=="1" (
if not defined t goto e
set "e=%t:~-4%"
if /i "!e!"==".txt" (set "o=%t:~0,-4%") else (set "o=%t%")
if not exist "!o!.txt" goto e
if /i "%n%"=="1" (
ffmpeg -f concat -safe 0 -i "!o!.txt" -c copy "!o!" -y
) else (
ffmpeg -f concat -safe 0 -i "!o!.txt" -c copy -map_metadata -1 -map_chapters -1 -metadata:s handler_name= -metadata:s vendor_id= "!o!" -y
)
if /i not "%k%"=="1" del /q "!o!.txt"
goto e
)
if not defined t if not defined f goto e
for %%a in (%t%) do echo file '%%a'>>"%f%.txt"
if /i "%n%"=="1" (
ffmpeg -f concat -safe 0 -i "%f%.txt" -c copy "%f%" -y
) else (
ffmpeg -f concat -safe 0 -i "%f%.txt" -c copy -map_metadata -1 -map_chapters -1 -metadata:s handler_name= -metadata:s vendor_id= "%f%" -y
)
if /i not "%k%"=="1" del /q "%f%.txt"
:e
endlocal
And the bash translation
Translated by ChatGPT 5.1, not tested, should be fine.
#!/bin/bash
set -euo pipefail
e=
f=
k=
l=
m=
n=
o=
t=
while [ "$#" -gt 0 ]; do
case "$1" in
-l) l=1;;
-m) m=1;;
-k) k=1;;
-n) n=1;;
-*);;
*)
if [ -z "$t" ]; then
t="$1"
elif [ -z "$f" ]; then
f="$1"
fi
;;
esac
shift
done
if [ -n "$l" ]; then
if [ -z "$t" ] || [ -z "$f" ]; then exit 0; fi
for a in $t; do
printf "file '%s'\n" "$a" >> "${f}.txt"
done
exit 0
fi
if [ -n "$m" ]; then
if [ -z "$t" ]; then exit 0; fi
e="${t: -4}"
if [ "$e" = ".txt" ]; then
o="${t%.*}"
else
o="$t"
fi
if [ ! -f "${o}.txt" ]; then exit 0; fi
if [ -n "$n" ]; then
ffmpeg -f concat -safe 0 -i "${o}.txt" -c copy "$o" -y
else
ffmpeg -f concat -safe 0 -i "${o}.txt" -c copy -map_metadata -1 -map_chapters -1 -metadata:s handler_name= -metadata:s vendor_id= "$o" -y
fi
if [ -z "$k" ]; then rm -f "${o}.txt"; fi
exit 0
fi
if [ -z "$t" ] || [ -z "$f" ]; then exit 0; fi
for a in $t; do
printf "file '%s'\n" "$a" >> "${f}.txt"
done
if [ -n "$n" ]; then
ffmpeg -f concat -safe 0 -i "${f}.txt" -c copy "$f" -y
else
ffmpeg -f concat -safe 0 -i "${f}.txt" -c copy -map_metadata -1 -map_chapters -1 -metadata:s handler_name= -metadata:s vendor_id= "$f" -y
fi
if [ -z "$k" ]; then rm -f "${f}.txt"; fi