├── README.md └── janus-combine.sh /README.md: -------------------------------------------------------------------------------- 1 | # janus-combine-video 2 | Bash script to combine multiple MJR files created by Janus WebRTC gateway into a single WebM video 3 | 4 | This is a raw first attempt for now. 5 | It assumes the first video is the longest and that all files in the target folder is of the same session. 6 | -------------------------------------------------------------------------------- /janus-combine.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # janus-combine.sh 4 | # Combine multiple MJR recording files into one WeBM video file 5 | # Author: Marnus van Niekerk - m@mjvn.net 6 | # Dependencies: ffmpeg with filter_comlex support 7 | # 8 | # This is a raw first attempt. 9 | # For now it assumes the first video is the longest and the result is never longer than the first. 10 | # It also assumes that there are only files from one session on the target directory. 11 | # 12 | 13 | DEBUG=no 14 | if [ "X$1" == "X-x" ] 15 | then 16 | set -x 17 | DEBUG=yes 18 | shift 19 | fi 20 | 21 | # Check that at least one argument is passed and that it is a directory 22 | if [ $# -lt 1 -o ! -d "$1" ] 23 | then 24 | echo "USAGE: [-x] $0 dir [output]" >&1 25 | exit 1 26 | fi 27 | 28 | # Change to target directory 29 | DIR="$1" 30 | cd $DIR 31 | 32 | # Clean up any previous attempt 33 | /bin/rm -f *.webm *.opus 34 | 35 | # List of video files 36 | FILES=`/bin/ls -1 *video.mjr | sort -t- -k5 | sed 's/-video.mjr//g'` 37 | CNT=`echo $FILES | wc -w` 38 | 39 | # Convert all video files to WebM and OPUS and combine 40 | # Calculate time differences in the same loop 41 | i=0 42 | BASEts=0 43 | ENDts=0 44 | dt="unknown" 45 | DIFF=0 46 | TMPFILE=`mktemp` 47 | for FILE in $FILES 48 | do 49 | janus-pp-rec $FILE-video.mjr $FILE-video.webm 50 | if [ $FILE-audio.mjr ] 51 | then 52 | janus-pp-rec $FILE-audio.mjr $FILE-audio.opus 53 | ffmpeg -i $FILE-audio.opus -i $FILE-video.webm -c:v copy -c:a opus -strict experimental $FILE-video-combined.webm 54 | else 55 | /bin/cp $FILE-video.webm $FILE-video-combined.webm 56 | fi 57 | start_ts=`echo $FILE | cut -f5 -d-` 58 | dur=`ffmpeg -i $FILE-video.webm /dev/null 2>&1 | fgrep Duration | cut -d" " -f4- | cut -d, -f1` 59 | dur=`date +%s%N -d "1970-01-01 $dur UTC"` 60 | end_ts=$(($start_ts + $dur/1000)) 61 | 62 | # Absolute start and end of call 63 | if [ $BASEts = 0 ] 64 | then 65 | BASEts=$start_ts 66 | tmp=`echo $BASEts | cut -c1-10` 67 | dt=`date -d @$tmp "+%Y%m%d%H%M%S"` 68 | fi 69 | [ $end_ts -gt $ENDts ] && ENDts=$end_ts 70 | 71 | DIFF=$(($start_ts-$BASEts)) 72 | DIFFms=`echo "scale=0;$DIFF/1000" | bc` 73 | DIFFs=`echo "scale=4;$DIFF/1000000" | bc` 74 | 75 | # Save variables to temp file for execution later 76 | echo "FILE$i=$FILE-video-combined.webm" >> $TMPFILE 77 | echo "DIFF$i=$DIFF" >> $TMPFILE 78 | echo "DIFFs$i=$DIFFs" >> $TMPFILE 79 | echo "DIFFms$i=$DIFFms" >> $TMPFILE 80 | echo "start_ts$i=$start_ts" >> $TMPFILE 81 | echo "end_ts$i=$end_ts" >> $TMPFILE 82 | 83 | i=$(($i+1)) 84 | done 85 | TMP=$(($ENDts - $BASEts)) 86 | DURms=$(($TMP / 1000)) 87 | DURs=$(($DURms / 1000 + 1)) 88 | echo "DURms=$DURms" >> $TMPFILE 89 | echo "DURs=$DURs" >> $TMPFILE 90 | 91 | # Set variables saved to file during loop 92 | [ $DEBUG == "yes" ] && cat $TMPFILE 93 | source $TMPFILE; /bin/rm -f $TMPFILE 94 | 95 | # Name of output file 96 | if [ $# -gt 1 ] 97 | then 98 | OUT="$2" 99 | else 100 | OUT=`basename $DIR`.$dt.webm 101 | fi 102 | 103 | 104 | # Now construct a command to create the combined video 105 | if [ $CNT -eq 1 ] # Only 1 video 106 | then 107 | /bin/mv $FILE0 $OUT 108 | fi 109 | 110 | if [ $CNT -eq 2 ] # 2 videos 111 | then 112 | ffmpeg -i $FILE0 -i $FILE1 -filter_complex \ 113 | "[0]pad=2*iw:ih[l];[1]setpts=PTS-STARTPTS+$DIFFs1/TB[1v]; [l][1v]overlay=x=W/2[v]; \ 114 | [1]adelay=$DIFFms1|$DIFFms1[1a]; \ 115 | [0][1a]amix=inputs=2[a]" \ 116 | -map "[v]" -map "[a]" $OUT 117 | fi 118 | 119 | if [ $CNT -eq 3 ] # 3 videos 120 | then 121 | ffmpeg -i $FILE0 -i $FILE1 -i $FILE2 -filter_complex \ 122 | "[0]pad=2*iw:2*ih[l];[1]setpts=PTS-STARTPTS+$DIFFs1/TB[1v]; [l][1v]overlay=x=W/2[a]; \ 123 | [2]setpts=PTS-STARTPTS+$DIFFs2/TB[2v]; [a][2v]overlay=y=H/2[v]; \ 124 | [1]adelay=$DIFFms1|$DIFFms1[1a]; [2]adelay=$DIFFms2|$DIFFms2[2a]; \ 125 | [0][1a][2a]amix=inputs=3[a]" \ 126 | -map "[v]" -map "[a]" $OUT 127 | fi 128 | 129 | if [ $CNT -gt 3 ] # More than 3, combine only the first 4 130 | then 131 | ffmpeg -i $FILE0 -i $FILE1 -i $FILE2 -i $FILE3 -filter_complex \ 132 | "[0]pad=2*iw:2*ih[l];[1]setpts=PTS-STARTPTS+$DIFFs1/TB[1v]; [l][1v]overlay=x=W/2[a]; \ 133 | [2]setpts=PTS-STARTPTS+$DIFFs2/TB[2v]; [a][2v]overlay=y=H/2[b]; \ 134 | [3]setpts=PTS-STARTPTS+$DIFFs3/TB[3v]; [b][3v]overlay=y=H/2:x=W/2[v]; \ 135 | [1]adelay=$DIFFms1|$DIFFms1[1a]; [2]adelay=$DIFFms2|$DIFFms2[2a]; \ 136 | [3]adelay=$DIFFms3|$DIFFms3[3a]; \n 137 | [0][1a][2a][3a]amix=inputs=4[a]" \ 138 | -map "[v]" -map "[a]" $OUT 139 | fi 140 | 141 | # Clean up 142 | /bin/mv $OUT $OUT.protect #safety net in case name matches below 143 | /bin/rm -f *combined.webm *video.webm *.opus 144 | /bin/mv $OUT.protect $OUT 145 | --------------------------------------------------------------------------------