handbrakecli/ffmpeg command to encode and auto filename(Ubuntu) - ffmpeg

I have 2 preset .json files(from the GUI version on windows) to convert mkv to mp4.
converts to h264 and adds subtitle 1
converts to h264
I'm only trying to get no.2 to work at this stage.
for i in `*.mkv`; do HandBrakeCLI --preset-import-file HPRESET.json -Z "MYPRESET" --output *.mp4; done
no output name
HandBrakeCLI -i $1 --preset-import-gui HPRESET.json -Z "MYPRESET" --output $1.mp4
errors on output name
for i in `*.mkv`; do HandBrakeCLI --title $i --preset "Very Fast 1080p30" --output *.mp4; done
errors on output name AND not valid preset.
$ for i in `seq 4`; do HandBrakeCLI --input /dev/dvd --title $i --preset Normal --output NameOfDisc_Title$i.mp4; done
copied this from another stackoverflow question, but outputs as 1.mp4 and then 2.mp4 etc.

You can extract the filename without extension with something like that:
noext=${i%.*}
Example:
╰─$ for i in *.mkv; do echo "$i"; noext=${i%.*}; echo "$noext"; done
asdf.mkv
asdf
test.mkv
test
Same loop, different notation:
for i in *.mkv
do
#put the commands you want to run after "do" and before "done"
echo "$i"
noext=${i%.*}
echo "$noext"
done
Note that the for command will search any file in the current directory ending with .mkv. For each file it has found, it will save the files name into the variable $i, then execute the commands after do, then save the next files name into the variable $i and execute the commands between do and done. It will repeat that cycle until every file which has been found is processed.
As I have no experience with handbrake presets, here a solution with ffmpeg:
for i in *.mkv
do
#put the commands you want to run after "do" and before "done"
noext=${i%.*}
ffmpeg -i "$i" -c:v libx264 -c:a copy -c:s copy "$noext.mp4"
done

Related

How to make bunch of stereo files from bunch of mono files with ffmpeg in bash?

I have two folders "Left channel" and "Right channel". Each folder contains mono files with same names. Example: "Left channel" contains "A.wav", "B.wav", "C.wav" and "Right channel" contains "A.wav", "B.wav", "C.wav". I need to make stereo files for each mono files.
So I have to combine
ffmpeg -i left.mp3 -i right.mp3 -filter_complex "[0:a][1:a]join=inputs=2:channel_layout=stereo[a]" -map "[a]" output.mp3
and
for file in /dir/* do ffmpeg -i ...; done
How can I go through all mono files and make bunch of stereo files from these mono files with ffmpeg in bash?
Would you please try the following:
#!/bin/bash
lch="Left channel"; rch="Right channel" # directory names of wav files
for f in "dir/$lch/"*.wav; do
fname=${f##*/} # filename such as "A.wav"
outfile="output_${fname%.*}.mp3" # output filename such as "output_A.mp3"
if [[ -f dir/$lch/$fname && dir/$rch/$fname ]]; then
echo ffmpeg -i "dir/$lch/$fname" -i "dir/$rch/$fname" -filter_complex "[0:a][1:a]join=inputs=2:channel_layout=stereo[a]" -map "[a]" "$outfile"
fi
done
It just outputs the command line as a dry run. If the output looks good, drop echo and run again.
Please note the output of echo removes the double quotes around the filenames. If you copy the output of echo and execute it on the command line, it will not work well.

While loop in bash to read a file skips first 2 characters of THIRD Line

#bin/bash
INPUT_DIR="$1"
INPUT_VIDEO="$2"
OUTPUT_PATH="$3"
SOURCE="$4"
DATE="$5"
INPUT="$INPUT_DIR/sorted_result.txt"
COUNT=1
initial=00:00:00
while IFS= read -r line; do
OUT_DIR=$OUTPUT_PATH/$COUNT
mkdir "$OUT_DIR"
ffmpeg -nostdin -i $INPUT_VIDEO -vcodec h264 -vf fps=25 -ss $initial -to $line $OUT_DIR/$COUNT.avi
ffmpeg -i $OUT_DIR/$COUNT.avi -acodec pcm_s16le -ar 16000 -ac 1 $OUT_DIR/$COUNT.wav
python3.6 /home/Video_Audio_Chunks_1.py $OUT_DIR/$COUNT.wav
python /home/transcribe.py --decoder beam --cuda --source $SOURCE --date $DATE --video $OUT_DIR/$COUNT.avi --out_dir "$OUT_DIR"
COUNT=$((COUNT + 1))
echo "--------------------------------------------------"
echo $initial
echo $line
echo "--------------------------------------------------"
initial=$line
done < "$INPUT"
This is the code I am working on.
The contents of file sorted_results.txt are as follows:
00:6:59
00:7:55
00:8:39
00:19:17
00:27:48
00:43:27
While reading the file it skips first two characters of the third line i.e. it takes it as :8:39 which results in the ffmpeg error and the script stops.
However when I only print the variables $INITIAL and $LINE, commenting the ffmpeg command the values are printed correctly i.e. same as the file contents.
I think the ffmpeg command is somehow affecting the file reading process or the variable value. BUT I CAN'T UNDERSTAND HOW?
PLEASE HELP.
Your bash read builtin command and the second ffmpeg command (for the audio) both read from STDIN, that is why they interfere with each other. You can either also specify -nostdin there or use another file descriptor (here number 3 is used) for read:
while IFS= read -r -u 3 line; do
...
done 3< "$INPUT"

How to run ffmpeg in a loop and test it for error?

I have stuttering, seeking, and general playback issues when playing large mkv files through my Plex Media Server setup. I have been looking around for a way to automate scheduled tasks to move everything to mp4. The objective is:
Copy mkv files into mp4 preserving subtitles of every kind. Put the new file in the same subdir, and delete previous mkv version if conversion went successful.
When I tried to run ffmpeg on a loop, I run into the problem described here:
https://unix.stackexchange.com/questions/36310/strange-errors-when-using-ffmpeg-in-a-loop
This is my first adventure on shell scripting and I am pretty much stumbling around and trying to understand the syntax and philosophy of it. What I understand is that they use a file descriptor to redirect ffmpeg output to /dev/null.
The problem with that solution is that I would need to check ffmpeg output for errors to decide whether to delete the previous file or not. Furthermore, there is a common error when converting from picture based subtitles streams, which I circumvent by using a script I found (http://www.computernerdfromhell.com/blog/automatically-extract-subtitles-from-mkv/) to work after some modifications to my needs.
After much frustration I ended modifying the script so much that it does not serve to its purpose. It does not check for errors. Anyways, I will post it here. Mind you that this is my first shell script ever, and almost everything is confusing about it. The problem with this, is that I had to ditch my error checking and I am eliminating files that errored when converting. Losing the original without a valid copy.
#!/bin/bash
FOLDERS=( "/mnt/stg4usb/media0/test/matroska1" "/mnt/stg4usb/media0/test/season1" "/mnt/stg4usb/media0/test/secondtest")
FLAGS="-y -metadata title="" -c:v copy -map 0 -c:a libfdk_aac -ac 2 -movflags +faststart"
COUNTER=0
LOGFILE=batch-$(date +"%Y%m%d-%H%M%S").log
for FOLDER in "${FOLDERS[#]}"
do
echo "---===> STARTING folder: '$FOLDER'"
find $FOLDER -name "*.mkv" | while read line; do
OUTPUT=""
DATE=$(date +"%Y-%m-%d")
TIME=$(date +"%H:%M:%S")
COUNTER=$((COUNTER+1))
FILE=$(basename "$line")
DIR=$(dirname "${line}")
echo $'\n'$'\n'"[$COUNTER][$DATE][$TIME][FILE:'${line%.mkv}.mp4']"$'\n'
echo "#### Transcoding ####"'\n'
ffmpeg -i $line $FLAGS -sn "${line%.mkv}.mp4" < /dev/null
echo "#### Extracting subtitles ###"'\n''\n'
mkvmerge -i "$line" | grep 'subtitles' | while read subline
do
# Grep the number of the subtitle track
tracknumber=`echo $subline | egrep -o "[0-9]{1,2}" | head -1`
# Get base name for subtitle
subtitlename=${line%.*}
# Extract the track to a .tmp file
mkvextract tracks "$line" $tracknumber:"$subtitlename.$tracknumber.srt" < /dev/null
chmod g+rw "$subtitlename.$tracknumber"* < /dev/null
done
rm -frv "$line" < /dev/null
echo "Finished: $(date +"%Y%m%d-%H%M%S")"
done
echo '\n'"<===--- DONE with folder: '$FOLDER'"$'\n'$'\n' >> $LOGFILE
done
exit 0
So, basically, the idea is: run ffmpeg on a loop for all mkv under a directory and subdirectories (I was using find). Check it for all possible errors. If errors, try again without subtitles and extract the subtitles using mkvextract, else everything went ok, and delete the previous file.

FFmpeg script skips files

I wrote a shell script to convert many video files and save them with something appended to the file name. The script works, but it seems to randomly skip files, and a lot of them.
When I re-run the script, it will convert files it skipped before. How can I get it to stop skipping files?
workingDir=/home/user/Videos
# get list of files to convert
find /video/folder -iname "*.mp4" > $workingDir/file_list
# convert files
cat $workingDir/file_list | while read LINE; do
# FFmpeg often cuts off the beginning of this line
echo "$(dirname "$LINE")/$(basename "$LINE")"
if /usr/bin/ffmpeg -n -loglevel panic -v quiet -stats -i "$LINE" \
-c:v libx264 -vf scale="trunc(oh*a/2)*2:320" \
-pix_fmt yuv420p -preset:v slow -profile:v main -tune:v animation -crf 23 \
"$(dirname "$LINE")/$(basename "$LINE" \.mp4)"_reencoded.mp4 2>/dev/null; then
echo "Success: $(dirname "$LINE")/$(basename "$LINE")" >> $workingDir/results
else
echo "Failed: $(dirname "$LINE")/$(basename "$LINE")" >> $workingDir/results
fi
done
One problem seems to be that FFmpeg interferes with the script. The FFmpeg output often cuts off the beginning of the next command, even if the output is not shown. This is demonstrated by the echo line before the if statement, which is often cut off. But even for lines that aren't cut off, most of them will be skipped for no apparent reason.
ffmpeg reads from stdin, thereby consuming input meant for while read. Just redirect stdin for ffmpeg by adding < /dev/null

Bad bitrate in 3gp file, convert to mp3 using ffmpeg

I record calls on my phone (as audio only). Records are storing to 3gp file. When I play a single file it can be mentioned that it is plaing few times faster then normal speed of conversation. I tested, that played on ffplay using command
ffplay.exe %1 -ar 8000
sounds as a real speed.
I would like to convert 3gp file to mp3 file using ffmpeg file (easy batch script running on Windows). I started with command line
ffmpeg.exe -i %1 -ar 8000 -f mp3 %1.mp3
but bitaire of mp3 don't sounds well (too fast). I performed experiments with -b, -b:a and others parameters but bitrate does not change.
Which parameters have I use to change 3gp to mp3 file with proper bitrate value?
-ar 8000
forces ffmpeg to interpret your input file as being sampled at 8kHz. Is tis the case or are you trying to downsample it to 8 kHz?
If so try the following instead:
-af "aresample=8000"
Please mark this as good answer if you're happy with it ;)
Well the commands you have fired are correct. I myself tried them myself and are working correctly. So firstly just try again with 1 file rather than batch files.
Here is command 1
ffmpeg -i input.3gp -ar 32k -f mp3 out.mp3
Result
Bitrate of out.mp3 is 47kbps
Command 2
ffmpeg -i inout.3gp -b:a 32k out.mp3
Bitrate of out.mp3 32kbps
So you can go with any of the above.
Cheers :)
Below you will find a script that I altered to include .3gp files.
It also does .mp4 .mkv and .webm files.
The clarity of the voice was good at 30k and that is what is here, but if you want larger files with better sound clarity then try 200k.
Call your script file vidconvmp3.sh for example and save it.
Then Modch +x vidconvmp3.sh to authorize execute.
then ./vidconvmp3.sh and your batch will run through and toss your mp3 files into a folder called Desktop-mp3 if you run terminal on the desktop... tah dah.
#!/usr/bin/env bash
# My bash Script to convert mp4 to mp3
# By NerdJK23
# web: www.computingforgeeks.com
# email: kiplangatmtai#gmail.com
# Requires
# ffmpeg installed
# lame installed
# Check https://computingforgeeks.com/how-to-convert-mp4-to-mp3-on-linux/
echo -ne """
1: Current directory
2: Provide directory
"""
echo ""
echo -n "Selection : "
read selection
case $selection in
1)
echo "Okay.."
echo ""
echo "Current dir is `pwd` "
;;
2)
echo ""
echo -n "Give diretory name: "
read dir_name
# Check if given directory is valid
if [ -d $dir_name ]; then
cd "${$dir_name}"
echo "Current directory is `pwd` "
echo
else
echo "Invalid directory, exiting.."
echo ""
exit 10
fi
echo
;;
*)
echo
echo "Wrong selection"
exit 11
;;
esac
echo ""
# Create dir to store mp3 files if it doesn't exist
# First get the current directory name
current_dir=`pwd`
base_name=` basename "$current_dir"`
if [[ ! -d "$base_name"-mp3 ]]; then
echo "$base_name" | xargs -d "\n" -I {} mkdir {}-mp3
echo ""
fi
echo ""
# Bigin to covert videos to mp3 audio files
# -d "\n" > Change delimiter from any whitespace to end of line character
find . -name "*.mp4" -o -name "*.mkv" -o -name "*.webm" -o -name "*.3gp" | xargs -d "\n" -I {} ffmpeg -i {} -b:a 30K -vn "$base_name"-mp3/{}.mp3
# remove video extensions
cd "${base_name}"-mp3
for file_name in *; do
mv "$file_name" "`echo $file_name | sed "s/.mp4//g;s/.mkv//g;s/.3pg//g;s/.webm//g"`";
done
# Move audio directory to ~/Music
if [[ ! -d ~/Music ]]; then
mkdir ~/Music
fi
cd ..
mv "$base_name"-mp3 ~/Music/
# Check if conversion successfull
echo ""
if [[ $? -eq "0" ]];then
echo " All files converted successfully"
else
echo "Conversation failed"
exit 1
fi

Resources