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
Related
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
I have a short bash script that is meant to convert a folder full of .mp3 files to .m4r ringtones. I am having trouble figuring out why it is throwing the following error:
"Error: ExtAudioFileCreateWithURL failed ('fmt?')"
#!/bin/bash
cd "/path/to/directory/containing/mp3s"
for i in *.mp3; do
baseFilename=$( basename ${i} .mp3 )
afconvert -f m4af ${i} -o "/path/to/new/location/${baseFilename}.m4r"
done
exit 0
The issue was that I had not specified the output data format. Found a helpful page that lead me to the answer:
http://support.moonpoint.com/os/os-x/audio/afconvert.php
#!/bin/bash
cd "/path/to/directory/containing/mp3s"
for i in *.mp3; do
baseFilename=$( basename "${i}" .mp3 )
afconvert -f m4af "${i}" -d aac "/path/to/new/location/${baseFilename}.m4r"
done
exit 0
I'm currently using a bash shell script to encode all of my Plex DVR recordings to H.264 using FFMPEG. I'm using this little for loop I found online to encode all of the files in a single directory:
for i in *.ts;
do echo "$i" && ffmpeg -i "$i" -vf yadif -c:v libx264 -preset veryslow -crf 22 -y "/mnt/d/Video/DVR Stash/Seinfeld/${i%.*}.mp4";
done
This has served its purposes well but in the process I would like to rename the file to my preferred naming convention so that the original filename Seinfeld (1989) - S01E01 - Pilot.ts is renamed to Seinfeld S01 E01 Pilot.mp4 in the encoded file. While I am already using a regular expression to change the .ts extension to .mp4, but I'm no expert with regex, especially in the bash shell so any help would be appreciated.
For anyone that's interested in my Plex setup, I'm using an old machine running Linux Mint as my dedicated DVR and actually accessing it over the network with my daily driver which is a gaming machine, so more processing power for video encodes. While that one is a Windows machine, I'm using the Ubuntu bash under WSL2 to run my script, as I prefer it over the Windows command prompt or Powershell (my day job is a web developer on a company issued Mac). So here's a sample of my code for anyone that might consider doing something similar.
if [[ -d "/mnt/sambashare/Seinfeld (1989)" ]]
then
cd "/mnt/sambashare/Seinfeld (1989)"
echo "Seinfeld"
for dir in */; do
echo "$dir/"
cd "$dir"
for i in *.ts;
do echo "$i" && ffmpeg -i "$i" -vf yadif -c:v libx264 -preset veryslow -crf 22 -y "/mnt/d/Video/DVR Stash/Seinfeld/${i%.*}.mp4";
done
cd ..
done
fi
While I've considered doing a for loop for all shows, for now I am doing each show like this individually as there are a few shows I have custom encoding settings for
A small revision from your code, something like this, with extglob
#!/usr/bin/env bash
if [[ -d "/mnt/sambashare/Seinfeld (1989)" ]]; then
cd "/mnt/sambashare/Seinfeld (1989)" || exit
echo "Seinfeld"
for dir in */; do
echo "$dir/"
cd "$dir" || exit
for i in *.ts; do
shopt -s extglob
new_file=${i//#( \(*\)|- )}
new_file=${new_file/E/ E}
new_file=${new_file%.*}
echo "$i" &&
ffmpeg -i "$i" -vf yadif -c:v libx264 -preset veryslow -crf 22 -y "/mnt/d/Video/DVR Stash/Seinfeld/${new_file}.mp4"
shopt -u extglob
done
cd ..
done
fi
The string/glob/pattern slicing might fail if there is/are E's in the file name somewhere besides the episode.
With BASH_REMATCH using the =~ operator for Extended Regular Expression. This will work even if there are more E's in the filename.
#!/usr/bin/env bash
if [[ -d "/mnt/sambashare/Seinfeld (1989)" ]]; then
cd "/mnt/sambashare/Seinfeld (1989)" || exit
echo "Seinfeld"
for dir in */; do
echo "$dir/"
cd "$dir" || exit
for i in *.ts; do
regex='^(.+) (\(.+\)) - (S[[:digit:]]+)(E[[:digit:]]+) - (.+)([.].+)$'
[[ $i =~ $regex ]] &&
new_file="${BASH_REMATCH[1]} ${BASH_REMATCH[3]} ${BASH_REMATCH[4]} ${BASH_REMATCH[5]}"
echo "$i" &&
ffmpeg -i "$i" -vf yadif -c:v libx264 -preset veryslow -crf 22 -y "/mnt/d/Video/DVR Stash/Seinfeld/${new_file}.mp4"
done
cd ..
done
fi
Added a cd ... || exit just to make sure that the script stops/exits if there is/are errors when trying to cd to somewhere and not to continue the script.
This bash script takes a cctv screenshot on cronjob, daily.
The filenames are saved YY_MM_DD_HH_MM_SS.
I can make a 'year to date' timelapse (comes out as sofar.gif) easily using the below line -- note that this ignores all filenames / creation dates and just sued every JPG in the folder ffmpeg -pattern_type glob -i $outdir/'*.jpg' $outdir/gif/sofar.gif -y
But I also want to generate at the same time, a gif using EITHER:
A) the JPG's with the most recent 7x file names
B) the JPG's with the most recent modified stamp
(same result)
I have tried this code below, which does generate a 7days.gif but it only contains 1 frame, the 7th oldest screenshot -- rather my desired output having 7 frames made up from the most 7x recent screenshots.
#!/usr/bin/env bash
PATH=/usr/local/bin:/usr/local/sbin:~/bin:/usr/bin:/bin:/usr/sbin:/sbin
# runs from a cronjob. saves live screenshot from CCTV to jpg, then updates the year-to-date movie
if [ $# -ne 1 ]
then
echo "Usage: `basename $0` OUTDIR"
exit 65
fi
doexit=0
start=$(date +%s)
end=$(date +%s)
outdir=${1%/}
mkdir $outdir
mkdir $outdir/gif/
echo "Capturing image..."
counter=$(date +"%Y_%m_%d_%H-%M-%S");
file=$outdir/$counter.jpg
if response=$(curl --silent --write-out %{http_code} --max-time 600 'http://192.168.1.69/cgi-bin/snapshot.cgi?chn=0&u=XXX&p=XXX&q=0&d=1&rand=0.14620004288649113' -o $file) ; then
echo "Captured & saved $file!"
else
echo "Failed to capture $file"
fi
# THIS IS THE BIT WHICH DOES THE LAST 7 DAYS
shopt -s nullglob
files=( "$outdir"/*.jpg )
file_count=${#files[#]}
echo
if (( ${#files[#]} == 0 )); then
echo "ERROR: No files found" >&2; exit 1;
elif (( ${#files[#]} > 7 )); then
files=( "${files[#]:$(( ${#files[#]} - 7 ))}" )
fi
input_args=( )
for f in "${files[#]}"; do
input_args+=(-i "$f")
done
echo "Making weekly.."
echo "${input_args[#]}"
echo "Making weekly.."
ffmpeg "${input_args[#]}" $outdir/gif/7days.gif -y
echo "Making YTD.."
ffmpeg -hide_banner -loglevel panic -pattern_type glob -i $outdir/'*.jpg' $outdir/gif/sofar.gif -y
exit 1
The code half works as if I echo the ${input_args[#]} I see the correct file list; Making weekly.. -i 365/2019_07_10_15-00-00.jpg -i 365/2019_07_11_15-00-00.jpg -i 365/2019_07_12_15-00-00.jpg -i 365/2019_07_13_15-00-00.jpg -i 365/2019_07_14_15-00-00.jpg -i 365/2019_07_15_15-00-00.jpg -i 365/2019_07_16_12-00-19.jpg which seems to confuse ffmpeg it because it adds the -i over & over, meaning the gif only has one frame.
I need to edit the script above to correctly also spit out a 7days.gif which is dynamically made using the most recent 7x screenshots in $outdir
If you want the seven most recent files, and since your filenames do not contain newlines, you can do:
readarray -t files < <( ls -tr | tail -7 )
I have a bash script which runs on a cron, to take screenshots of my cctv 1x per day to do an annual timelapse. It all works, and I get a YTD sofar.gif of the very first screenshot to the very last screenshot -- which is now quite long. I wanted to add a line to make last7days.gif so I could get a shorter weekly gif etc.
I have searched this site and the web and can list the newest 7 files in terminal using: ls -1t | head -n 9 | tail -n 7 (this removes the .gif and .mov which are modified last) but I do not know how to make that vertical list of 7 filenames into a variable to make a gif using those file names
# runs from a cronjob. saves live screenshot from CCTV to jpg, then updates the year-to-date movie
if [ $# -ne 1 ]
then
echo "Usage: `basename $0` OUTDIR"
exit 65
fi
doexit=0
start=$(date +%s)
end=$(date +%s)
outdir=${1%/}
mkdir $outdir
echo "Capturing image..."
counter=$(date +"%Y_%m_%d_%H-%M-%S");
file=$outdir/$counter.jpg
if response=$(curl --silent --write-out %{http_code} --max-time 600 'URL REDACTED' -o $file) ; then
echo "Captured & saved $file!"
else
echo "Failed to capture $file"
fi
ffmpeg -hide_banner -loglevel panic -pattern_type glob -i $outdir/'*.jpg' $outdir/sofar.mov -y
ffmpeg -hide_banner -loglevel panic -pattern_type glob -i $outdir/'*.jpg' $outdir/sofar.gif -y
exit 1
Currently, the last lines create a .gif using every image file, this works only because they are saved with the date in the filename.
I want to add a line to create a .gif using just the most 7 recent images
Do the globbing in the shell, then you can take whatever subset you want:
#!/usr/bin/env bash
# ^^^^- NOT /bin/sh; array support is required.
shopt -s nullglob
files=( "$outdir"/*.jpg )
file_count=${#files[#]}
if (( ${#files[#]} == 0 )); then
echo "ERROR: No files found" >&2; exit 1;
elif (( ${#files[#]} > 7 )); then
files=( "${files[#]:$(( ${#files[#]} - 7 ))}" )
fi
input_args=( )
for f in "${files[#]}"; do
input_args+=( -i "$f" )
done
ffmpeg "${input_args[#]}" "$outdir/sofar.gif"