Script to compress selected video files using FFmpeg

1 Like

The solution was:
for filelist in *.mp4;

I missed ; and spent hours searching forums…:grimacing:

1 Like

@Andrius I had time to take a look at your issue today.

Here you will find a script which does what you want - it transcodes any number of input files one by one - following Bash best practices:

I hope it helps you learn a thing or two.
There’s a lot of bad advice floating about regarding Bash. Here are the two best Bash resources you can trust:
http://mywiki.wooledge.org/FullBashGuide
http://wiki.bash-hackers.org/syntax/pe
http://wiki.bash-hackers.org/commands/classictest

2 Likes

Hello Morgan,
Thank you very much for taking the time to look into this.
I wish I saw your script before writing mine. :slight_smile:

The script works just fine but what I what I found out is that actually some metadata gets lost/changed during the ffmpeg conversion even though the -map_metadata 0 option is activated.
Bento4 SDK Suit can copy the atoms containing the metadata from the original file to the compressed one.
So I am trying to add the following actions to the script:
First of all, download bento4 SDK and add the arguments to the script: (I guess you can skip this step if you compiled it from sources.)
mp4extract="/path/to/static/build/mp4extract"
mp4edit="/path/to/static/build/mp4edit"
Then
# Do the conversion.
count="1"
for f in "$@"; do
Step 1 - Extraction of the udta atom from each video file (filename.mp4) to a corresponding txt file (filename.txt):
mp4extract moov/udta "${f}" ${f%.*}.txt
Step 2 - Compression of each original video file (filename.mp4) to filename_suffix.mp4 using ffmpeg:
ffmpeg -i "${f}" -y -f mp4 -c:a "${ca}" -b:a "${ba}" -c:v "${cv}" -crf "${crf}" -preset "${preset}" -map_metadata 0 "${f%.*}_${cv}_${crf}_${preset}.mp4" || exit 1
Step 3 - Import the metadata from the txt files (filename.txt) to the compressed mp4 videos (filename_suffix.mp4).
Here is the code I wrote for this:
for FILE in *.txt;
do
BASE=${FILE%.txt}
if [ -e "$BASE.txt" ]; then
echo -e "\033[1;34m Importing metadata from "$BASE.txt" to "$BASE.mp4" / "$BASE_gps.mp4"\033[0m"
mp4edit --insert moov:"$BASE.txt" "$BASE.mp4" "$BASE_gps.mp4"
fi
done
but I don’t know if the code actually works. I simply don’t get to the step 3 because the step 1 does not work.
The command works just fine when I run it in the terminal and drag a file there, e.g.
/path/to/Bento4-SDK-1-5-0-614.x86_64-unknown-linux/bin/mp4extract moov/udta '/path/to/filename.mp4' '/path/to/filename.txt'
but if mp4extract being called via a script I get this error:
Open: open(moov/udta) failed (src/mp4file.cpp,398)
I am wondering why there is a difference between running mp4extract in the terminal and calling it via a bash script. Any ideas?
https://www.bento4.com/

I suggest you build whatever changes you need on top of my file because the code above continues the mistakes I found in your original.

As for copying metadata, I’d first try the far more common and readily avialable ExifTool:
exiftool -TagsFromFile in.mp4 out.mp4
http://www.sno.phy.queensu.ca/~phil/exiftool/exiftool_pod.html#COPYING-EXAMPLES

@Morgan_Hardwood I just finished working on version 1.0 of the script and wondering what is the right way to publish it on GitHub. I created a repository but not sure how I can upload a file there. Also I can create a gist but I don’t know what gist is. Gists are a pain in the neck to find from mobile device as well. Can you advise ?

Do you want to publish to the pixls repo or your own?

It does not really matter for me.I bet my scripts will need to be polished a lot prior to be published at pixls.us

If you like to add it to the pixls repo, you’d for the repo, add your changes, then make a pull request on github.

It makes a clone of the whole repo when I do this. Is this fine ?

Yes, you’ll add your change to your fork of the repo, push back to github, then it should prompt you to make a pull request.

@Andrius maybe its better if you first experiment with your own repo for some weeks before pushing to pixls to avoid breakage. There are plenty of resources - especially the Git Handbook and youtube. Happy to help if you run into trouble. Creating a git repo is easy.

Ok, I think I am online now:
https://github.com/AndriusWild/dam_scripts/blob/master/compress2mp4

I can pull changes from the web via git pull origin master but when I am trying to push them back from my PC to the server git push origin master I get a message Everything up-to-date but the changes are not being pushed back to git.
Does it matter how big the changes are? I just changed license from GPL to GPLv3 to check the functionality

I think I see your change at Update compress2mp4 · AndriusWild/dam_scripts@8204f98 · GitHub

That’s the one I made on the webpage. I was able to pull it from my laptop. But I can’t push anything back to GitHub though… it says everything is up to date even though I know it is not

Hello, I figured out how to use GitHub and released v1.0-bash of my script called compress2mp4.
The main purpose of the script is compressing video files created by cameras and mobile phones to free up space on HDD.
Compression is lossy; output format is h.264; container is mp4.
Compression ratio really depends on the input file and is usually higher for MOV files created by digital cameras and Apple iPhones and lower for MP4 files created by Android phones (probably because Android already applied some sort of compression to them).
Script consists of few modules:

  1. Basic module - compress using ffmpeg. Constant Rate Factor set to 23 by default (the value recommended by FFmpeg team).
  2. Check compression ratio. If it is less than 1.5 the file will be re-compressed with CRF 26 (lower quality, lower output file size)
  3. Import [udta] atom from the original to the output using Bento4 SDK. This step required if you want to be able to see your compressed videos on the map from your Android phone. Apparently some information gets lost during the compression even though “-map_metadata 0” option is activated. For videos created by iPhones you will have to copy and paste the [meta] atom (moov/meta) instead.
  4. Verify GPS information of the output files using MediaInfo. Apparently ffmpeg is not able to catch the error.
  5. Write FileModifyDate from Quicktime Create Date. This step required if you want to see compressed videos in correct chronological order in digiKam. Apparently exiv2 which digiKam relies on is capable of reading metadata from some certain video formats only (none of the video files I had were detected correct).
  6. Delete temporary files and move originals to specified folder (I will be deleting originals from that folder after a year or so).
    One can delete unwanted modules.

Future plans:

  1. Rewrite the script in python. Just because I want to learn python for my second hobby - automation where python being used extensively.
  2. Add an ability to write GPS information into sidecar xmp files that will be recognized by digiKam.

Special thanks to @Morgan_Hardwood who helped me to get started.
Any comments and critics are welcome.
Stay tuned for future releases!

1 Like

I created a service menu to launch the script:

[Desktop Entry]
Type=Service
ServiceTypes=KonqPopupMenu/Plugin
MimeType=video/x-msvideo;video/quicktime;video/mpeg;video/mp4;
Icon=folder-video
Actions=compress2mp4
X-KDE-Priority=TopLevel
X-KDE-StartupNotify=false
X-KDE-Submenu=Video

[Desktop Action compress2mp4]
Name=Compress to mp4
Icon=video-mp4
Exec="\\$HOME/Scripts/Git/compress2mp4.sh" %F

But I keep getting this error:
Could not find the program '\$HOME/Scripts/Git/compress2mp4.sh'

It is weird because the same Exec line in .desktop file for ‘open with’ menu works just fine.
Does anyone know what is the issue here?

You don’t need \\ in front of $HOME.

I tried that but it did not do the trick.

Is the script executable? If not, chmod +x it end remove those two backslashes from the desktop file.