ffmpeg not working in script - moov atom not found - linux

I made a simple script that divides a flv file into multiple parts, converts them all to .mp4 individually and then merge all of them to form a final mp4 file. I did this to save time and convert large files in parallel.
However, I am stuck because the command that normally runs on command line for ffmpeg, doesn't run via script.
I am kind of stuck here and will like to have some assistance.
#!/bin/bash
#sleep 5
filenametmp=$1;
filename=`echo "$filenametmp" | awk '{split($0,a,"."); print a[1]}'`
echo $filename
output="$filename-output"
filenamewithoutpath=`echo "$output" | awk '{split($0,a,"/"); print a[4]}'`
echo $output $filenamewithoutpath
/usr/bin/ffmpeg -i $filenametmp -c copy -map 0 -segment_time $2 -f segment $output%01d.flv
#sleep 10
#echo "/bin/ls -lrt /root/storage/ | /bin/grep $filenamewithoutpath | /usr/bin/wc -l"
filecounttmp=`/bin/ls -lrt /opt/storage/ | /bin/grep $filenamewithoutpath | /usr/bin/wc -l`
filecount=`expr $filecounttmp - 1`
echo $filecount
for i in `seq 0 $filecount`
do
suffix=`expr 0000 + $i`
filenametoconvert="$output$suffix.flv"
convertedfilename="$output$suffix.mp4"
echo $filenametoconvert
/usr/bin/ffmpeg -i $filenametoconvert -c:v libx264 -crf 23 -preset medium -vsync 1 -r 25 -c:a aac -strict -2 -b:a 64k -ar 44100 -ac 1 $convertedfilename > /dev/null 2>&1 &
done
sleep 5
concatstring=""
for j in `seq 0 $filecount`
do
suffix=`expr 0000 + $j`
convertedfilenamemp4="$output$suffix.mp4"
#concatstring=`concat:$concatstring|$convertedfilenamemp4`
echo "file" $convertedfilenamemp4 >> $filename.txt
#ffmpeg -i concat:"$concatstring" -codec copy $filename.mp4
#ffmpeg -f concat -i $filename.txt -c copy $filename.mp4
done
echo $concatstring
ffmpeg -f concat -i $filename.txt -c copy $filename.mp4
rm $output*
rm $filename.txt
I run any flv file like this :
./ff.sh /opt/storage/tttttssssssssss_573f5b1cd473202daf2bf694.flv 20
I get this error message :
moov atom not found
I am on Ubuntu 14.04 LTS version, standard installation of ffmpeg.

Related

ffmpeg messes up variables [duplicate]

This question already has answers here:
Bash script stops execution of ffmpeg in while loop - why?
(3 answers)
Execute "ffmpeg" command in a loop [duplicate]
(3 answers)
Closed 7 days ago.
I am trying to split audio files by their chapters. I have downloaded this as audio with yt-dlp with its chapters on. I have tried this very simple script to do the job:
#!/bin/sh
ffmpeg -loglevel 0 -i "$1" -f ffmetadata meta # take the metadata and output it to the file meta
cat meta | grep "END" | awk -F"=" '{print $2}' | awk -F"007000000" '{print $1}' > ends #
cat meta | grep "title=" | awk -F"=" '{print $2}' | cut -c4- > titles
from="0"
count=1
while IFS= read -r to; do
title=$(head -$count titles | tail -1)
ffmpeg -loglevel 0 -i "$1" -ss $from -to $to -c copy "$title".webm
echo $from $to
count=$(( $count+1 ))
from=$to
done < ends
You see that I echo out $from and $to because I noticed they are just wrong. Why is this? When I comment out the ffmpeg command in the while loop, the variables $from and $to turn out to be correct, but when it is uncommented they just become some stupid numbers.
Commented output:
0 465
465 770
770 890
890 1208
1208 1554
1554 1793
1793 2249
2249 2681
2681 2952
2952 3493
3493 3797
3797 3998
3998 4246
4246 4585
4585 5235
5235 5375
5375 5796
5796 6368
6368 6696
6696 6961
Uncommented output:
0 465
465 70
70 890
890 08
08 1554
1554 3
3 2249
2249
2952
2952 3493
3493
3998
3998 4246
4246 5235
5235 796
796 6368
6368
I tried lots of other stuff thinking that they might be the problem but they didn't change anything. One I remember is I tried havin $from and $to in the form of %H:%M:%S which, again, gave the same result.
Thanks in advance.
Here is an untested refactoring; hopefully it can at least help steer you in another direction.
Avoid temporary files.
Avoid reading the second input file repeatedly inside the loop.
Refactor the complex Awk scripts into a single script.
To be on the safe side, add a redirection from /dev/null to prevent ffmpeg from eating the input data.
#!/bin/sh
from=0
ffmpeg -loglevel 0 -i "$1" -f ffmetadata - |
awk -F '=' '/END/ { s=$2; sub(/007000000.*/, "", s); end[++i] = s }
/title=/ { t=$2; sub(/^([^-]-){3}/, "", t); title[++j] = t }
END { for(n=1; n<=i; n++) print end[n]; print title[n] }' |
while IFS="" read -r end; do
IFS="" read -r title
ffmpeg -loglevel 0 -i "$1" -ss "$from" -to "$end" -c copy "$title".webm </dev/null
from="$end"
done
The Awk script reads all the data into memory, and then prints one "end" marker followed by the corresponding title on the next line; I can't be sure what your ffmpeg -f ffmetadata command outputs, so I just blindly refactored what your scripts seemed to be doing. If the output is somewhat structured you can probably read one record at a time.

function in loop corrupts every other iteration

I made a short bash program to download podcasts and retrieve only last 20 seconds.
Strange thing is it fails downloading every other iteration. There seems to be a problem with the function trim_nsec, because when I get rid of it in the loop, all the rest correctly works.
Edit : addition of double quotes, which doesn't solve the problem
<!-- language: lang-bash -->
#!/bin/bash
# Get podcast list
wget -O feed http://www.rtl.fr/podcast/on-n-est-pas-forcement-d-accord.xml
function trim_nsec () {
# arguments : 1 : mp3file - 2 : duration - 3 : outputfile
duration=$(ffprobe -i "${1}" -show_entries format=duration -v quiet -of csv="p=0")
nth_second=$(echo "${duration} - ${2}"|bc)
ffmpeg -i "${1}" -ss "${nth_second}" "${3}"
}
cpt=1
# let's work only on the 4th first files
grep -Po 'http[^<]*.mp3' feed|grep admedia| head -n 4 > list
cat list | while read i
do
year=$(echo "$i" | cut -d"/" -f6)
day=$(echo "$i" | cut -d"/" -f7)
fullname=$(echo "$i" | awk -F"/" '{print $NF}')
fullnameend=$(echo "$fullname" |sed -e 's/\.mp3$/_end\.mp3/')
new_name=$(echo "$year"_"$day"_"$fullnameend")
# let's download
wget -O "$fullname" "$i"
# let's trim last 20 sec
trim_nsec "$fullname" 20 "$new_name"
echo "$cpt file processed"
#delete orig. file :
rm "$fullname"
((cpt++))
done
Any idea ?
The problem is most likely due to the fact that on errors, ffmpeg will try to get an input from user which will consume the input provided by cat list. See a similar question here or here. To prevent trim_nsec from consuming the input from cat list, you could do:
cat list | while read i
do
year=$(echo "$i" | cut -d"/" -f6)
day=$(echo "$i" | cut -d"/" -f7)
fullname=$(echo "$i" | awk -F"/" '{print $NF}')
fullnameend=$(echo "$fullname" |sed -e 's/\.mp3$/_end\.mp3/')
new_name=$(echo "$year"_"$day"_"$fullnameend")
# let's download
wget -c -O "$fullname" "$i"
# let's trim last 20 sec
trim_nsec "$fullname" 20 "$new_name" <&3
echo "$cpt file processed"
#delete orig. file :
#rm "$fullname"
((cpt++))
done 3<&1

How to detect the silence at the end of an audio file?

I am trying to detect silence at the end of an audio file.
I have made some progress with ffmpeg library. Here I used silencedetect to list all the silences in an audio file.
ffmpeg -i audio.wav -af silencedetect=n=-50dB:d=0.5 -f null - 2> /home/aliakber/log.txt
Here is the output of the command:
--With silence at the front and end of the audio file--
[silencedetect # 0x1043060] silence_start: 0.484979
[silencedetect # 0x1043060] silence_end: 1.36898 | silence_duration: 0.884
[silencedetect # 0x1043060] silence_start: 2.57298
[silencedetect # 0x1043060] silence_end: 3.48098 | silence_duration: 0.908
[silencedetect # 0x1043060] silence_start: 4.75698
size=N/A time=00:00:05.56 bitrate=N/A
--Without silence at the front and end of the audio file--
[silencedetect # 0x106fd60] silence_start: 0.353333
[silencedetect # 0x106fd60] silence_end: 1.25867 | silence_duration: 0.905333
[silencedetect # 0x106fd60] silence_start: 2.46533
[silencedetect # 0x106fd60] silence_end: 3.37067 | silence_duration: 0.905333
size=N/A time=00:00:04.61 bitrate=N/A
But I want something more flexible so that I can manipulate the output and do further task depending on the result.
I want to get the output something like true or false. If there is a certain period of silence exists at the end of the audio file it will return true and false otherwise.
Can someone suggest me an easy way to achieve this?
Try this:
ffmpeg -i audio.wav -af silencedetect=n=-50dB:d=0.5 -f null - 2>&1 | grep -Eo "silence_(start|end)" | tail -n 1 | grep "start" | wc -l
Output:
1 - there is silence at the end
0 - there is no silence at the end
Explanation:
As I see in the silence case there is no silence_end at the end of log.
2>&1 - redirect stderr to stdin
grep -Eo "silence_(start|end)" - filter log and keep only silence_start and silence_end from log. Each by new line.
tail -n 1 - get last line. (if it is. So now we there are 3 cases of state: 'silence_start', 'silence_end', <empty>)
grep "start" - keep line only if it contains start (2 cases: 'silence_start', <empty>)
wc -l - get number of lines. (1 in 'silence_start' and 0 in <empty> case)
The answer from #tarwirdur-turon doesn't work for me (in 2023 and ffmpeg version 5.1.2).
I came up with a somewhat convoluted script to do it. Convoluted, because it does error checking.
It uses 2 calls: ffprobe + ffmpeg to find reliably the duration of the audio file and tests it against the last silence_end by divison of the found values, which should be very close to 1.00. You can change the scale for calculating the division and various other values at the beginning of the script.
#! /bin/bash
set -e
INPUT="$1"
NOISE_FLOOR="-60db"
MIN_DUR=0.1
SCALE=2
[ -z "$INPUT" ] && echo "Needs audio file !" && exit 1
echo -n "$INPUT ends with silence: "
dur=$(ffprobe -i $INPUT -show_entries format=duration -v quiet -of csv="p=0" 2>&1)
if [ -z "$dur" ]; then
echo "FALSE" && exit 1
fi
# xargs alone trims spaces
last_silence_end=$(ffmpeg -i $INPUT -af silencedetect=noise=$NOISE_FLOOR:d=$MIN_DUR -f null - 2>&1 | grep silence_end | tail -n 1 | cut -d ' ' -f 5)
if [ -z "$last_silence_end" ]; then
echo "FALSE" && exit 0
fi
factor=$(bc <<<"scale=$SCALE; $dur / $last_silence_end")
if [ "$factor" == "1.00" ]; then
echo "TRUE"
else
echo "FALSE"
fi
exit 0

ffmpeg generate m3u8 from mp4 (Resume option)

I have a mp4 file or other file (non mp4 format) and i need generate ts files and m3u8 playlist.
I am using this command and works fine:
ffmpeg -i foo.mp4 -codec copy -vbsf h264_mp4toannexb -map 0 -f segment
-segment_list out.m3u8 -segment_time 10 out%03d.ts
Now I need to generate many ts simultaneous so i need a "resume option".
Please see the example below:
One thread (first 20 seconds (0-20))
ffmpeg -i foo.mp4 -codec copy -vbsf h264_mp4toannexb -map 0 -f segment
-segment_list out.m3u8 -segment_time 10 out%03d.ts
Seconds thread (20 seconds to 40 seconds)
ffmpeg -i foo.mp4 ......
Third thread (40 seconds to 60 seconds)
ffmpeg -i foo.mp4 ......
I have lots of core processor to do this jobs.
In resume i need generate .ts files and m3u8 fastest way possible
I need help or advises to resolve my problem.
Prove of concept i build a litle script that use -ss and -t option:
<?php
//generate all the commands using -ss and -t <seconds>
$startTime = new DateTime("00:00:00");
for ($i=1; $i < 20; $i++) {
$data = $startTime->format('H:i:s');
$exec = 'ffmpeg -i "<FILE>" -ss '.$data.' -t 10 -c:v copy -bsf h264_mp4toannexb -flags -global_header -map 0 -f segment -segment_time 10 -segment_start_number '.$i.' -segment_list '.sprintf("%04d", $i).'_test.m3u8 -segment_format mpegts '.$i.'stream%05d.ts';
shell_exec($exec);
$startTime->modify('+10 seconds');
echo "\n";
}
//cycle all m3u8 and creates a master hls playlist
$files = glob('*.{m3u8}', GLOB_BRACE);
sort($files);
$ret = "#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:11
";
foreach($files as $file) {
$ret .= shell_exec('sed -n -e 6,7p '. $file);
}
$ret .= "#EXT-X-ENDLIST";
file_put_contents('final.m3u8', $ret);
?>
Thanks

Improve avconv load and speed?

When I convert video through avconv it's take above 95% percentage, is there any way to reduce the converting time?
Try using -threads auto or push it to the number of cores / threads your CPU has.
Here is my full script
#!/bin/sh
infile=$1
tmpfile="$1-tmp.mp4"
outfile="$1-new.mp4"
options="-vcodec libx264 -b 512k -flags +loop+mv4 -cmp 256 \
-partitions +parti4x4+parti8x8+partp4x4+partp8x8+partb8x8 \
-me_method hex -subq 7 -trellis 1 -refs 5 -bf 3 \
-flags2 +bpyramid+wpred+mixed_refs+dct8x8 -coder 1 -me_range 16 \
-g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10\
-qmax 51 -qdiff 4"
# Half size
options=$options" -vf scale=iw*0.5:-1"
# Copy audio
options=$options" -codec:a copy"
# Shut up
options=$options" -loglevel info "
# echo "Options : $options"
avconv -y -i "$infile" -threads auto $options "$outfile"
# avconv -y -i "$infile" -an -pass 1 -threads auto $options "$tmpfile"
# avconv -y -i "$infile" -acodec aac -strict experimental -ar 44100 -ab 96k -pass 2 -threads auto $options "$tmpfile"
# qt-faststart "$tmpfile" "$outfile"

Resources