====== Stack two videos side-by-side with ffmpeg ====== I created a Unix shell script to do a **side-by-side comparison** between videos recorded with my two action cameras: a new **SJCAM 8 Pro** and the old **Xiaomi Yi**. Suppose that we have two videos taken simultaneously with the two cameras: {{.:ffmpeg:video1.jpg?320|}} {{.:ffmpeg:video2.jpg?320|}} The result will be a video like the following: the **central part** of each video is stacked horizontally on the final frame, two **labels are overlayed** on the bottom corners, the **audio** from the first video is mixed into the **left channel** of the resulting video and the audio from the second video goes to the **right channel**. {{.:ffmpeg:video_hstack.jpg?640|}} The script uses **ffmpeg** to do all the incantation. It is required that both videos share **the same resolution**. The script can take into account that the videos may be **out of sync**: it is possible to pass **two timestamps** referring at the same instant captured into both videos. The script will **shift the videos presentation time** each-other, so that both will be synced. The script has some constraints. It requires the **Bash shell**, because it uses the **%%((expression))%%** to do arithmetic evaluation. The script requires also the **Python** interpreter, just to do a floating point difference and properly formats the result. #!/bin/bash # Take the central part of two videos and stack them horizontally. # Audio from the first video is merged into the left channel of the # resulting video, audio from the second video goes to the right. # Two lables are overlayed on the bottom left and right corners. # https://stackoverflow.com/questions/35349935/ffmpeg-crop-with-side-by-side-merge # https://unix.stackexchange.com/questions/233832/merge-two-video-clips-into-one-placing-them-next-to-each-other # https://trac.ffmpeg.org/wiki/AudioChannelManipulation # Left and right videos. #VIDEO_1='20211023135104_0322.MP4' #VIDEO_2='YDXJ0851.mp4' VIDEO_1="$1" VIDEO_2="$2" # Two timestamps which should be synced. #TIME_1='15.482' #TIME_2='16.282' TIME_1="$3" TIME_2="$4" # Labels to be superimposed on the two halves. #LABEL_1='SJ8Pro' #LABEL_2='Xiaomi Yi' LABEL_1="$5" LABEL_2="$6" #OUTPUT='output.mkv' OUTPUT="$7" if [ -z "$VIDEO_1" -o -z "$VIDEO_2" -o \ -z "$TIME_1" -o -z "$TIME_2" -o \ -z "$LABEL_1" -o -z "$LABEL_2" -o \ -z "$OUTPUT" ]; then echo echo "Usage: $(basename $0) [video1] [video2] [time1] [time2] [label1] [label2] [output]" echo echo " Example: $(basename $0) 20211023135104_0322.MP4 YDXJ0851.mp4 15.482 16.282 SJ8Pro 'Xiaomi Yi' output.mkv" echo exit 1 fi # Do the math, etc... if (( $(echo "$TIME_1 > $TIME_2" | bc -l) )) ; then TO_1="$(python -c "print('%0.3f' % ($TIME_1 - $TIME_2,))")" TO_2='0.000' else TO_1='0.000' TO_2="$(python -c "print('%0.3f' % ($TIME_2 - $TIME_1,))")" fi # Font and style for labels. FONT='fontfile=/usr/share/fonts/truetype/msttcorefonts/Arial_Bold.ttf:' STYLE='fontcolor=yellow:fontsize=48:box=1:boxcolor=black@0.5:boxborderw=10' # Labels placement. L1X='20' L2X='(w-text_w-20)' L1Y='(h-text_h-20)' L2Y='(h-text_h-20)' ffmpeg -ss "$TO_1" -i "$VIDEO_1" -ss "$TO_2" -i "$VIDEO_2" \ -filter_complex \ "[0:v]crop=iw/2:ih:ow/2:0[left]; \ [1:v]crop=iw/2:ih:ow/2:0[right]; \ [left][right]hstack=shortest=1[vs]; \ [0:a][1:a]amerge=inputs=2,pan=stereo|c0