How can I sync the frames of multiple videos from a multi-camera capture system using FFMPEG - bash

I have a multi-camera capture setup with 2 canon cameras. Each of these cameras have a tentacle sync e timecode generator connected to them.
After a video capture with these 2 cameras, the generated timecode (SMPTE format) is stored in the video files metadata.
It looks like this 00:00:53;30
Is there a bash script that uses FFmpeg to trim the start time of the video that started earlier (based on timecode) to match the other and then trim the end time of the video that ended last to match the one that ended first?
The two trimmed output videos should be synced based on the timecode and have the same duration.
So far, my bash script looks like this:
file1="A001C002_220101EB_CANON.MXF"
file2="A001C002_220101US_CANON.MXF"
# Get the SMPTE timecodes of the two files
timecode1=$(ffmpeg -i "$file1" 2>&1 | sed -n 's/timecode.*: \(.*\)/\1/p')
timecode2=$(ffmpeg -i "$file2" 2>&1 | sed -n 's/timecode.*: \(.*\)/\1/p')
# Convert the SMPTE timecode to start time in seconds
start_time_1=$(echo "$timecode1" | awk -F ':' '{print 3600*$1 + 60*$2 + $3}')
start_time_2=$(echo "$timecode2" | awk -F ':' '{print 3600*$1 + 60*$2 + $3}')
# Trim the start of the video with the earlier start timecode so that both videos have the same start time
if [ "$start_time_1" -lt "$start_time_2" ]; then
ffmpeg -i "$file1" -ss "$start_time_2" -c:v libx264 -crf 18 -preset veryfast trimmed_file1.mp4
ffmpeg -i "$file2" -c:v libx264 -crf 18 -preset veryfast trimmed_file2.mp4
else
ffmpeg -i "$file2" -ss "$start_time_1" -c:v libx264 -crf 18 -preset veryfast trimmed_file2.mp4
ffmpeg -i "$file1" -c:v libx264 -crf 18 -preset veryfast trimmed_file1.mp4
fi
# Get the duration of both files
duration_1=$(ffmpeg -i trimmed_file1.mp4 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,//)
duration_2=$(ffmpeg -i trimmed_file2.mp4 2>&1 | grep "Duration" | cut -d ' ' -f 4 | sed s/,//)
# Convert the duration to seconds
duration_1_secs=$(echo $duration_1 | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
duration_2_secs=$(echo $duration_2 | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
# Trim the end time of the video that ended last to match the one that ended first
if [ "$duration_1_secs" -gt "$duration_2_secs" ]; then
echo "Trimming end time of file1 to match file2"
ffmpeg -i trimmed_file1.mp4 -t "$duration_2" -c:v libx264 -c:a aac trimmed_file1.mp4
else
echo "Trimming end time of file2 to match file1"
ffmpeg -i trimmed_file2.mp4 -t "$duration_1" -c:v libx264 -c:a aac trimmed_file2.mp4
fi
But this does not make the videos have matching frames.
Thanks!

Related

How to the stream should be automatically restart after 10 seconds if the stream cut

I will restart using this script . But sometime for some reason the stream goes cut....
How to the stream should be automatically restart after 10 seconds if the stream cut.
#!/bin/bash
while true;do
grep -c "Non-monotonous DTS in output stream" file.txt >nonmonotonus.txt
grep -c "Timestamps are unset in a packet for stream" file.txt >timestamp.txt
grep -c "PES packet size mismatch" file.txt >pespacket.txt
grep -c "Error while decoding stream" file.txt >errordecoding.txt
grep -c "Circular buffer overrun" file.txt >circularbuffer.txt
grep -c "Header missing" file.txt >header.txt
grep -c "Conversion failed" file.txt >conversion.txt
file=nonmonotonus.txt
file1=timestamp.txt
file2=pespacket.txt
file3=errordecoding.txt
file4=circularbuffer.txt
file5=header.txt
file6=conversion.txt
if (($(<"$file")>=3000)) || (($(<"$file1")>=500)) || (($(<"$file2")>=100)) || (($(<"$file3")>=1000)) || (($(<"$file4")>=500)) || (($(<"$file5")>=6)) || (($(<"$file6")>=1)); then
stream1 restart > restart.txt
sleep 1
fi
done
__________________________________________________________________________
FFmpeg -re -threads 3 -c:s webvtt -i "$INPUT_URL?source=null&overrun_nonfatal=1&fifo_size=1000000" \
-c:v copy \
-map 0:0 -map 0:1 \
-c:a aac -b:a 128k -ar 48000 \
-threads 4 -f hls -hls_time 2 -hls_wrap 15 \
"manifest.m3u8" \
</dev/null > /dev/null 2>&1 2>file.txt & echo $! > $STREAM_PID_PATH
How to automatically restart the stream.. after cut the .ts file
Thankyou ...

TimeStamp variable stopped working in bash script with avconv

The following script was working fine until I upgraded all my Raspberry Pis to Release 9:
#!/bin/bash
cd /home/pi/Videos/SecurityCam/
DToday=`date '+%Y%m%d-%H%M%S'`
fn="VID $DToday"
SubT="PP $PB $DToday"
avconv -f video4linux2 -i /dev/video0 -t 3600 -r 4 -vf "drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf: \text=\'$SubT \%T \' : fontcolor=white#0.8: x=7: y=460" -vcodec libx264 -vb 2000k \-y ${fn}.avi
It is now choking on the %T. Why would that be and what is the right way to get a rolling timestamp in the video?
try with this:
#!/bin/bash
cd /home/pi/Videos/SecurityCam/ || exit
DToday=$(date '+%Y%m%d-%H%M%S')
fn="VID $DToday"
SubT="PP $PB $DToday"
avconv -f video4linux2 -i /dev/video0 -t 3600 -r 4 -vf "drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf: \text=\'$SubT \%T \' : fontcolor=white#0.8: x=7: y=460"
-vcodec libx264 -vb 2000k -y "${fn}.avi"

FFmpeg batch convert multiple files

This command works great:
ffmpeg \
-i /mnt/share/Movies2/"nameofmovie.mkv" \
-map 0:0 \
-map 0:1 \
-map 0:2 \
-c:v libx264 \
-preset veryfast \
-tune film \
-crf 18 \
-c:a:0 copy \
-c:a:1 copy \
/mnt/share/Converted/"nameofmovie".mkv
But i want to either be able to read the input file from a text file or to run this command one after another for each file i want to convert. Is there a script i can set up to do this? Not all the files are in the same folder or the same format so something where i could just change the file name and format would be great. I used to have a bash script that could do this for an entire folder but that's not what i am trying to do here. I am using Ubuntu server 18.04
Also i'm pretty new to this i've found this for a whole folder:
for i in *.avi;
do name=`echo $i | cut -d'.' -f1`;
echo $name;
ffmpeg -i "$i" "${name}.mov";
done
But i dont know how to adapt this for individual files
Create a text file the_list.txt as follows:
File1.mp4:mp4
File2.avi:avi
Here the first field is the filename, the second the source format (can be derived from file extenstion, but keeping it simple).
Create a script do_conv.sh:
cat the_list.txt | while read L
do
FNAME=$( echo $L | cut -d':' -f1 )
SRCFMT=$( echo $L | cut -d':' -f2 )
echo 'Next File: ${FNAME}"
if [ "${SRCFMT}" = "mp4" ]
then
ffmpeg -i ${FNAME} ....
elif [ "${SRCFMT}" = "mp4" ]
then
ffmpeg -i ${FNAME} ....
else
ffmpeg -i ${FNAME} ....
fi
done
Not sure exactly what conversion you want to be but hopefully this template can get you started.

PNG sequence to MP4 while looping the animation

So, I'm trying to convert a PNG sequence to an MP4 and loop the animation about 100 times, the only problem is my script doesn't seem to be working properly.
What the script is supposed to do is get the number of PNG files in the frames directory, and send them to FFMPEG 100 times. Only problem is my script isn't working right. Here's the code.
#!/bin/bash
loopcode()
{
tmpdir=frames
picext=png
one=$(ls -l ${tmpdir}/*.png | wc -l)
two=$(echo "${one}+0" | bc -l)
three=0
while [ ! ${loopi} -eq ${looper} ]; do
while [ ! ${three} -eq ${two} ]; do
three=$(printf "%09d" ${two})
echo ${tmpdir}/${three}.${picext}
two=$(echo "${two}+1" | bc -l)
done
two=0
loopi=$(echo "${loopi}+1" | bc -l)
done
}
looper=100
loopi=0
outfile=output.mp4
fps=5
convert frames/*.png frames/%09d.jpeg
loopcode && sleep 5
cat $(loopcode) | ffmpeg -framerate 1/5 -i - -c:v libx264 -r 30 -pix_fmt yuv420p "${outfile}"
You can skip the whole loop part in script and do it with ffmpeg i.e.
ffmpeg -r 1/5 -f lavfi -i "movie='a%d.png':loop=100" -c:v libx264 -r 30 -pix_fmt yuv420p "${outfile}"
This requires that the PNG image names form a continuous sequence.

Mixing two wav files in FFmpeg

I have 2 wav files wav1 and wav2.I want to play wav2 every 45 seconds
over the wav1 using FFmpeg.
Ok, first create a 45-second file to loop of wav2
ffmpeg -i wav2 -af apad -t 45 wav2-padded.wav
Now, the mix
ffmpeg -i wav1 -f lavfi -i amovie=wav2-padded:loop=9999 -filter_complex [0][1]amix[out] -map [out] -shortest mixed.wav
I think this should accomplish what you want
#!/bin/bash
interval_millis=45000
regex="Duration: ([0-9:.]+)"
[[ $(ffmpeg -i $1 2>&1) =~ $regex ]]
duration_millis=$(echo "${BASH_REMATCH[1]}" | \
awk -F: '{ print 1000 * (($1 * 3600) + ($2 * 60) + $3) }')
duration_counter=$interval_millis
i=1
while [[ $duration_counter -lt $duration_millis ]]; do
inputs+=" -i $2"
delay_params+="[$i]adelay=$duration_counter[del$i];"
amix_params+="[del$i]"
((i++))
((duration_counter += $interval_millis))
done
ffmpeg -i $1 $inputs -filter_complex \
"$delay_params[0]${amix_params}amix=inputs=$i:duration=first" out.wav
I had some problems with adelay on a 2015 build of ffmpeg, so make sure you have an up-to-date version to run this. You call the script as
./script.sh long-file short-file

Resources