TimeStamp variable stopped working in bash script with avconv - bash

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"

Related

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

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!

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 ...

Bash script to recursive find and convert movies

in my large movie collection I would like to search for movies with the primary (first) audio track with DTS coding to be converted to Dolby.
My problem would be the first track I think. My current bash script will list any movie containing a DTS track, but does not specify which track.
#!/bin/bash
# My message to create DTS list
find /home/Movies -name '*.mkv' | while read f
do
if mediainfo "$f" | grep A_DTS; then
echo $f
fi
done
After that I would like to run this command
ffmpeg -i $f -map 0:v -map 0:a:0 -map 0:a -map 0:s -c:v copy -c:a copy -c:s copy -c:a:0 ac3 -b:a:0 640k $f
or is there a way to move all the audio tracks down and adding the new AAC track?
###Progress
Thanks to #llogan I have finetuned the bash to find the required files.
#!/bin/bash
# My DTS conversion script
# credits to llogan
find /Mymovies -name '*.mkv' | while read f
do
if ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of csv=p=0 "$f" | grep dts; then
echo "$f"
fi
done
Now digging into the command I think I may have a working command. Anybody spot a problem?
ffmpeg -i $f
-map 0:v -c:v copy
-map 0:a:0? -c:a:0 ac3
-map 0:a:0? -c:a:1 copy
-map 0:a:1? -c:a:2 copy
-map 0:a:2? -c:a:3 copy
-map 0:a:3? -c:a:4 copy
-map 0:a:4? -c:a:5 copy
-map 0:a:5? -c:a:6 copy
-map 0:a:6? -c:a:7 copy
-map 0:a:7? -c:a:8 copy
-map 0:a:8? -c:a:9 copy
-map 0:s? -c copy
-b:a:0 640k
/tmp/output.mkv
mv $f /home/DTS_BACKUP/
mv /tmp/output.mkv $f
rm /tmp/output.mkv
So the end result would look like:
#!/bin/bash
# My DTS conversion script
# credits to llogan
find /Mymovies -name '*.mkv' | while read f
do
if ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of csv=p=0 "$f" | grep dts; then
ffmpeg -i $f
-map 0:v -c:v copy
-map 0:a:0? -c:a:0 ac3
-map 0:a:0? -c:a:1 copy
-map 0:a:1? -c:a:2 copy
-map 0:a:2? -c:a:3 copy
-map 0:a:3? -c:a:4 copy
-map 0:a:4? -c:a:5 copy
-map 0:a:5? -c:a:6 copy
-map 0:a:6? -c:a:7 copy
-map 0:a:7? -c:a:8 copy
-map 0:a:8? -c:a:9 copy
-map 0:s? -c copy
-b:a:0 640k
/tmp/output.mkv
mv $f /home/DTS_BACKUP/
mv /tmp/output.mkv $f
rm /tmp/output.mkv
fi
done
Ok, so i finetuned the script to seperate dts and dts-hd. I came to the conclusion this was not needed because i cant decode dts-hd to e-ac3 and may as well also encode it to ac3. But i had fun in bash.
Current bash:
#!/bin/bash
# My DTS conversion script
# credits to llogan
find /MyMovies -name '*.mkv' | while read f
do
function codec_profile {
ffprobe -v error -select_streams a:0 -show_entries stream=$1 -of csv=p=0 "$f"
}
#first check for audio format
if [ "$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of csv=p=0 "$f")" = "dts" ]; then
if [ "$(codec_profile "profile")" = "DTS" ]; then
echo "$f" >> dts.txt
codec_profile "profile" >> dts.txt
codec_profile "channels" >> dts.txt
if [ "$(codec_profile "channels")" -gt 5 ]; then
echo "check" >> dts.txt; else
echo "stereo" >> dts.txt;
fi
else [ "$(ffprobe -v error -select_streams a:0 -show_entries stream=profile -of csv=p=0 "$f")" = "DTS-HD MA" ];
echo "$f" >> dts-hd.txt
codec_profile "profile" >> dts-hd.txt
codec_profile "channels" >> dts-hd.txt
fi
fi
done
I checked the created txt files and the result is spot op. I also tested the command that #llogan gave me and works perfect.
ffmpeg -i "$f" -map 0 -map -0:a -map 0:a:0 -map 0:a -c copy -c:a:0 ac3 -b:a:0 640k /tmp/output.mkv
Last thing to figure out is how to check the exit code on this and replace the text file creation with this command
The idea:
ffmpeg -i "$f" -map 0 -map -0:a -map 0:a:0 -map 0:a -c copy -c:a:0 ac3 -b:a:0 640k /tmp/output.mkv
RC=$?
if [ "${RC}" -ne "0" ]; then
# list error in txt file and move on to next
else
# mv output file to overwrite original file
fi

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.

Loop with two variables at once in Bash

I have two file types with the same filenames in one directory:
file1.ts
file1.ec3
file2.ts
file2.ec3
and I need to make a loop which would process pair of files at once (file1.ts + file1.ec3).
Then the loop needs to be restarted with second pair (file2.ts + file2.ec3).
Here is my code:
for i in *.ts; do
for e in *.ec3; do
ffmpeg -i "$i" -i "$e" -map 0:v -map 1:a -codec copy "${i%.ts}_DD+.ts";
done;
done
But when the first cycle ends it tries to process file1.ts + file2.ec3 and brakes everything...
How can I make it work properly?
Try this:
for file in *.ts; do
[ -f "${file%.ts}.ec3" ] &&
ffmpeg -i "$file" -i "${file%.ts}.ec3" -map 0:v -map 1:a \
-codec copy "${file%.ts}_DD+.ts"
done

Resources