Disclaimer: I am just a guy who googled most of his knowledge when it was needed and there might be no cohesion at all. Sorry for this in advance.
I am writing a small script on my Ubuntu 18.04 server that should run a loop for encoding raw DVR files into easy to handle mp4. This "hard" part works fine already, I am just trying to get a clean script to let it run by the full hour. Unfortunately for whatever reason bash doesn't accept my if statement.
I tried dos2unix, semicolons, spacing, tabbing, intendation before and after the if statement but nothing worked. I scavenged almost all google results and stackoverflow-posts but nothing worked. I checked for hidden characters that could break the script. Still the error.
In the following script the XXX are placeholders for private stuff. Those lines already work.
#!/bin/bash
for file in $(find /var/www/vhosts/XXXXXX/* -name "*.h264");
if [ -z "$file" ]
then
echo "No new h264-files found. Exiting."; break
fi
do
echo "H264-files found. Calling ffmpeg for conversion to mp4."
ffmpeg -y -i "$file" -c:v libx264 -preset veryfast -crf 26 -an -sn "${file/h264/mp4}"
echo "Ffmpeg is finished."
#rm "$file" disabled until scripts works perfectly and is callable from plesk.
echo "All new files converted. Refreshing XXXXXcloud files."
sudo -u XXXX php /var/www/vhosts/XXXXX
echo "Script done."
done
I keep getting the following:
ffmpeg_transcode_h264tomp4.sh: line 3: syntax error near unexpected token `if'
ffmpeg_transcode_h264tomp4.sh: line 3: `if [ -z "$file" ]'
Using the ifne util and some advice from Charles Duffy, this should meet the spec:
find /var/www/vhosts/XXXXXX/* -name "*.h264" -print0 |
ifne -n echo "No new h264-files found. Exiting." |
while IFS= read -r -d '' file ; do
# ... more code goes here...
done
Related
I have a basic command (ffmpeg -i input_file out.srt) to turn .mkv video files to .srt subtitle files. The problem is that I have to manually run the command for every .mkv file. So I tried to implement a for loop in Bash, but I keep getting errors.
#!/bin/bash
# ffmpeg -i input_file out.srt
for i in *.mkv ; do
ffmpeg -i "$i" "$(basename "${i/.mkv)")".str
sleep 30
done
The two errors I get are:
./subcon.sh: line 6: unexpected EOF while looking for matching `}'
./subcon.sh: line 9: syntax error: unexpected end of file
I am not familiar with Bash to understand whats going on. Does anyone know where I can look stuff up or how to solve this particular problem?
Problems:
Mismatched brackets. Change { to (.
Incorrect subtitle extension. Change str to srt.
basename syntax is incorrect. Change "$(basename "${i/.mkv)")".str to "$(basename "$i" .mkv)".srt. Or use Bash parameter expansion instead of basename.
New script:
#!/bin/bash
# ffmpeg -i input_file out.srt
for i in *.mkv ; do
ffmpeg -i "$i" "$(basename "$i" .mkv)".srt
sleep 30
done
You can eliminate basename:
#!/bin/bash
# ffmpeg -i input_file out.srt
for i in *.mkv ; do
ffmpeg -i "$i" "${i%.*}.srt"
sleep 30
done
I recommend shellcheck.net to check your Bash scripts.
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.
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
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
So i've written a bash script to take newly written to video files and transcode them for playback and streaming in my server here is the script
while true; do
printf -v filename '%q' "$(inotifywait --format "%w""%f" -r -e close_write /var/$
echo $filename
if [[ $filename == *".mp4"* ]]; then
echo "1"
avconv -i "$filename" "`echo ${filename%.mp4}.webm`"
fi
if [[ $filename == *".mkv"* ]]; then
echo "2"
avconv -i "$filename" "`echo ${filename%.mkv}.mp4`"
avconv -i "$filename" "`echo ${filename%.mkv}.webm`"
fi
if [[ "$filename" == *".avi"* ]]
then echo "3"
avconv -i "$filename" "`echo ${filename%.avi}.mp4`" &
avconv -i "$filename" "`echo ${filename%.avi}.webm`"&
fi
done
The script works fairly well however if the $filename contains spaces avconv breaks and the script returns:
Watches established.
/var/www/media2net/tv/The\ Daily.mkv
2
avconv version 0.8.4-4:0.8.4-0ubuntu0.12.04.1, Copyright (c) 2000-2012 the Libav s
built on Nov 6 2012 16:51:33 with gcc 4.6.3
/var/www/media2net/tv/The\: No such file or directory
avconv version 0.8.4-4:0.8.4-0ubuntu0.12.04.1, Copyright (c) 2000-2012 the Libav
built on Nov 6 2012 16:51:33 with gcc 4.6.3
/var/www/media2net/tv/The\ Daily.mkv: No such file or directory
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
however this is not correct as I can view the said file inside it's respective directory, I also have tested avconv with the following in the shell and everything works properly and avconv transcodes video
avconv -i /var/www/media2net/The\ Daily.mkv /var/www/media2net/tv/The\ Daily.webm
Basically I am wondering what I am doing wrong in my script or if anyone else has experienced a similar problem using avconv or ffmpeg (as the 2 are fairly similar and avconv is ubuntu's fork of the project) any help would be greatly appreciated!
Thanks in advance
-brendan
There seems to be some inconsistencies in your usage of escape backslashes and quotes. In fact, you only need one of the two, and the easier to use is certainly the quotes.
So, to remove the backslashes in filenames would be the first good thing to do.
Additionally,
"$(inotifywait --format "%w""%f"...
should be corrected in :
"$(inotifywait --format '%w%f'...
Also, the lines which comprehend something like :
"`echo ${filename%.mkv}.mp4`"
are somewhat ambiguous, as in, fact, you are echoing - if there is a space in $filename - two chains of characters -. It should be corrected in :
"${filename/%.mkv/.mp4}"