Create PIP Video from two cameras
Post ReplyCreate PIP Video from two camerasPosted: Sunday, February 23, 2020 [20:47:07] - 1
If technical video required to include two source cameras this is a simple solution to make one. Perl code: ## Copyright 2020 CodeMacs.Com ## Program to collect videos and make PIP video from two cameras ## Requires install of ffmpeg and QTCoffe ## QTCoffe: www.3am.pair.com/ ## ffmpeg: ffmpeg.org/ # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, # copies of the Software, and to permit persons to whom the Software # is furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. use strict; use warnings; print "Please select video files directory: "; my $dir = <STDIN>; unless(-d $dir) {print "Directory $dir now found - exiting\n"; unless(-d "$dir/tmp") {`mkdir -p $dir/tmp`;} ## CREATE TEMP DIR ## SETTINGS FOR CUTTING VIDEO BY MARKERS my $beforemarker=4; my $aftermarker=6; ## Placement of PIP window my %fplace = ('br','overlay=W-w-XX:H-h-YY','bl','overlay=XX:H-h-YY','tr','overlay=W-w-XX:YY','tl','overlay=XX:YY'); ## PIP position and coordinates br - bottom right, bl - bottom left, tr - not right, tl - top left my $pipposition='overlay=50:50'; ## This can be further automated, replace XX and YY with pixels from appropriate side ## read file description at the bottom my $d = `cat $dir/timies.txt`; ## VIDEO FILES DATA WITH TIME MARKS WHERE TO CUT AND OFFSETS FOR PIP VIDEO my @all = split(/\n/,$d); my %offset=(); foreach my $l (@all) {my($file,$data); if($l =~ /___/) {$sw='overlay'; unless($sw) { ($file,$data) = split(/\t/,$l); my @tms = split(/\,/,$data); foreach my $t (@tms) {$t =~ s/ //g; } else {($file,$data)=split(/\t/,$l); getvidinfo($file,$sw); } ## FOREACH END chomp $mainfiles; chomp $overfiles; my @m = @main; @m = @over; ## create supporting video file to fill-up no video in PIP unless(-f "$dir/tmp/empty.mp4") { `ffmpeg -f lavfi -i color=c=blue:s=480x270:d=400 -vf "drawtext=fontfile=/Library/Fonts/digital-7.ttf:fontsize=80: fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:text='No Video'" -codec:v libx264 -an -crf 20 -preset slow -r $mfps $dir/tmp/empty.mp4`;} my $ovcmb=''; foreach my $f (@m) { ## Resize all PIP videos for the size unless($mfps == $ofps) { unless(-f "$dir/tmp/$f") { `ffmpeg -i $dir/$f -vf scale=480:270 -codec:v libx264 -an -crf 20 -preset slow -r $mfps $dir/tmp/$f`; } ## END UNLESS FILE ALREADY PRESENT } ## END DIFFERNET FPS $overmap{$f}=$ovrsecs; my $seconds = addtime($viddata{$f}{'duration min'},$viddata{$f}{'duration sec'}); if($offset{$f}) {my($omin,$osec) = split(/\:/,$offset{$f}); $mapover{$ovrsecs}=$mseconds; if($ovrsecs) {$lspace = $mseconds - $ovrsecs; else {$tocut=$offset{$f};} unless(-f "$dir/tmp/$fname.mp4") { #print "splitmovie $dir/tmp/empty.mp4 -splitAt $tocut -self-contained -o $dir/tmp/$fname.mp4\n"; `splitmovie $dir/tmp/empty.mp4 -splitAt $tocut -self-contained -o $dir/tmp/$fname.mp4`; if(-f "$dir/tmp/$fname\-2.mp4") {`rm $dir/tmp/$fname\-2.mp4`;} if(-f "$dir/tmp/$fname\-1.mp4") { `mv $dir/tmp/$fname\-1.mp4 $dir/tmp/$fname.mp4`; } } ## END UNLESS FILE PRESENT $ovcmb .= " $dir/tmp/$fname.mp4"; $ovrsecs += $mseconds; } ## END OFFSET PRESENT $ovcmb .= " $dir/tmp/$f"; $ovrsecs += $seconds; } # FOREACH OVER FILE END unless(-f "$dir/tmp/overlay.mp4") { print "catmovie$ovcmb -self-contained -o $dir/tmp/overlay.mp4\n"; `catmovie$ovcmb -self-contained -o $dir/tmp/overlay.mp4`; } ## END UNLESS OVERLAY PRESENT @m = @main; foreach my $f (@m) { $mcmb .= " $dir/$f"; my $seconds = addtime($viddata{$f}{'duration min'},$viddata{$f}{'duration sec'}); $mapmain{$f}=$mainsec; $mainsec += $seconds; } ## FOREACH FILE END unless(-f "$dir/tmp/main.mp4") { print "catmovie$mcmb -self-contained -o $dir/tmp/main.mp4\n"; `catmovie$mcmb -self-contained -o $dir/tmp/main.mp4`; } ## END UNLESS MAIN PRESENT print "Main Seconds: $mainsec\n"; print "Overlay Seconds: $ovrsecs\n"; ## Overlay is a PIP video my %making=(); my %delete=(); foreach my $f (sort keys(%splits)) {my $cuts=''; print "$dir/$f\n"; $nokeys = (keys %{$splits{$f}}); if($nokeys > 4) {$zero='0';} ## Make sure we match the auto-name files created by QTCoffe ## Procedure only support two digits auto increment, so if you have more than 49 markers per video - it will not work foreach my $t (sort keys %{$splits{$f}}) { $parts++; $delete{"$fn\-$zero$parts.$fe"}=1; $parts++; $making{$parts}{ma}="$fn\-$zero$parts.$fe"; $parts++; $delete{"$fn\-$zero$parts.$fe"}=1; my $secst=''; ## Video markers can be formatted either simply separated by commas 00:12, 03:45 etc. ## or full duration of the cut included and mixed i.e. 02:35-03:14, 05:15, 07:28 if($t =~ /\-/) { my($stt,$ett) = split(/\-/,$t); ($minst,$secst) = split(/\:/,$stt); ($minend,$secend) = split(/\:/,$ett); } else { ## END MATCHES HYPHEN ## Configure how much time before and after the marker needed to be included in a cut in seconds my($min,$sec) = split(/\:/,$t); } ## END REGULAR TIME if($secst < 0) {$minst--; if($secend > 59) {$minend++; if(length($secend) < 2) {$secend="0$secend";} if(length($secst) < 2) {$secst="0$secst";} if(length($minst) < 2) {$minst="0$minst";} if(length($minend) < 2) {$minend="0$minend";} print "\t\"$t\"\t$minst\:$secst - $minend\:$secend\n"; $cuts .= "$spr\-splitAt $minst\:$secst -splitAt $minend\:$secend"; my $stsecs = addtime($minst,$secst); my $ensecs = addtime($minend,$secend); $stsecs += $mapmain{$f}; my $startov = backtomin($stsecs); my $endov = backtomin($ensecs); $ovspl .= " -splitAt $startov -splitAt $endov"; } ## FOREACH TIME END my $code = "splitmovie $dir/$f $cuts -self-contained -o $dir/tmp/$f"; #print "\n$code\n"; `$code`; my $ovrlc = "splitmovie $dir/tmp/overlay.mp4$ovspl -self-contained -o $dir/tmp/$fn.ov.$fe"; ## Cut PIP by the same markers #print "$ovrlc\n"; `$ovrlc`; ## Combine main movie cut with PIP video foreach my $n (sort num keys (%making)) {$nmbcount++; `ffmpeg -i $dir/tmp/$making{$n}{ov} -i $dir/tmp/$making{$n}{ma} -filter_complex "[0]scale=iw/1:ih/1 [pip]; [1][pip] $pipposition" -codec:v libx264 -crf 20 -preset slow $dir/tmp/$nmbcount.$n.mp4`; $pushcomb .= " $dir/tmp/$nmbcount.$n.mp4"; print "\n\tMAKE: $nmbcount.$n.mp4\n\n"; $delete{"$nmbcount.$n.mp4"}=1; } ## FOREACH V NUMB END %making=(); } ## FOREACH FILES ## Combine all the cuts together print "catmovie$pushcomb -self-contained -o $dir/tmp/combined.mp4\n\n$pushcomb\n"; `catmovie$pushcomb -self-contained -o $dir/tmp/combined.mp4`; ## Remove temp files print "\nDeleting files:\n"; foreach my $f (sort keys(%delete)) { if(-f "$dir/tmp/$f") { print "$dir/tmp/$f\n"; `rm $dir/tmp/$f`; } } ## FOREAH DELETE END exit(0); sub num {$a <=> $b;} sub getvidinfo { my $file=shift; my $vinf = `ffmpeg -i $dir/$file 2>&1`; $vinf =~ s#\n(.*?)(Duration\:)\s(\d{2})\:(\d{2})\:(\d{2})\.(\d{2})(.*?)\n##; $vinf =~ s#\n(.*?)(Stream)(.*?)(\d{2}|\d{2}\.\d{2})\s(fps)(.*?)\n##; print "$file\nDuration: $durm\:$durs\nFPS: $fps\n"; $viddata{$file}{'duration min'}=$durm; } ## END GET VID INFO sub addtime { my($min,$sec) = @_; my $totsecs = $min * 60; } ## END SUB ADD TIME sub backtomin { my $s=shift; return sprintf ":%02d", $s if $s < 60; my $m = $s / 60; $s = $s % 60; return sprintf "%02d:%02d", $m, $s if $m < 60; my $h = $m / 60; $m %= 60; return sprintf "%02d:%02d:%02d", $h, $m, $s if $h < 24; my $d = $h / 24; $h %= 24; return sprintf "%d:%02d:%02d:%02d", $d, $h, $m, $s; } ## END BACK TO MINUTES Next, timies.txt file for program to properly cut videos. |
timies.txt file contentPosted: Sunday, February 23, 2020 [20:50:31] - 2
This file provides markers and offset information to properly build PIP video: Example: GP010150.MP4 GP020150.MP4 _________________ ch0_20200222170744_20200222171244.mp4 ch0_20200222171245_20200222171745.mp4 ch0_20200222171745_20200222172113.mp4 ch0_20200222172423_20200222172923.mp4 ch0_20200222172924_20200222173424.mp4 ch0_20200222173424_20200222173855.mp4 Explanations: # # # # # # # # # # # # As simple as that |
Video frame examplePosted: Sunday, February 23, 2020 [21:09:15] - 3