first public versions of kvm2png,al2fc,pngaac2mp4
This commit is contained in:
parent
fd2453c184
commit
598b94bf5f
@ -1,3 +1,7 @@
|
||||
# muxsa
|
||||
|
||||
muxsa (MUltipleXer for Slides and Audio): a collection of Linux tools for efficiently creating video files from presentation slides and background narration.
|
||||
|
||||
## Documentation
|
||||
* [Demonstration video (a.k.a. the making of Network Security 2020)](https://nks-devel3.rus.uni-stuttgart.de/muxsa/making_of_netsec_2020.mp4)
|
||||
* [muxsa block diagram](doc/muxsa-blockdiagram.png)
|
||||
|
108
bin/muxsa-al2fc
Executable file
108
bin/muxsa-al2fc
Executable file
@ -0,0 +1,108 @@
|
||||
#!/usr/bin/perl -w
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
# muxsa-al2fc
|
||||
#
|
||||
# part of muxsa, https://git-nks-public.tik.uni-stuttgart.de/edu/muxsa
|
||||
#
|
||||
# this script reads a "label track" that was exported by the
|
||||
# Audacity (https://www.audacityteam.org/) audio recoder/editor.
|
||||
# It assumes that the labels contain slide numbers.
|
||||
# It will output (to standard output) a sequence of statements that
|
||||
# can be read by the ffmpeg (https://ffmpeg.org/) concat multiplexer.
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Sebastian Kiesel <sebastian.kiesel@tik.uni-stuttgart.de>
|
||||
#
|
||||
# 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, sublicense,
|
||||
# and/or sell 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.
|
||||
|
||||
############################################################################
|
||||
|
||||
|
||||
sub printf_file {
|
||||
my $slide_prefix = $ENV{'MUXSA_KVM2PNG_SLIDE_PREFIX'}//"";
|
||||
if( $_[0] =~ /^[0-9]+$/ ){
|
||||
printf("file '%s%04i.png'\n", $slide_prefix, $_[0]);
|
||||
}
|
||||
else {
|
||||
printf("file '%s%s.png'\n", $slide_prefix, $_[0]);
|
||||
}
|
||||
}
|
||||
|
||||
sub printf_duration {
|
||||
printf("duration %.6f\n", $_[0]);
|
||||
}
|
||||
|
||||
############################################################################
|
||||
|
||||
my @cur;
|
||||
my @prev;
|
||||
|
||||
printf("# Beginning of ffmpeg concat sequence produced by muxsa-al2fc\n");
|
||||
|
||||
while(<>) {
|
||||
chomp();
|
||||
|
||||
# label start time, label end time, label text
|
||||
@cur = /^(-?[0-9]+\.[0-9]+)\t(-?[0-9]+\.[0-9]+)\t(.*)$/ or next;
|
||||
|
||||
if(!@prev){ # no previous label -> this is the first label we read
|
||||
if( $cur[0] != 0.0 ){
|
||||
printf("# Warning: 1st label ts changed: %.6f to 0.0\n", $cur[0]);
|
||||
$cur[0]=0.0;
|
||||
}
|
||||
@prev = @cur;
|
||||
next;
|
||||
}
|
||||
|
||||
my $duration = $cur[0] - $prev[0];
|
||||
printf("# Label \"%s\" from %.6f to %.6f duration %.6f\n",
|
||||
$prev[2], $prev[0], $cur[0], $duration);
|
||||
|
||||
while( $duration > 1.0 ){
|
||||
printf_file($prev[2]);
|
||||
printf_duration(1.0);
|
||||
$duration-=1.0;
|
||||
}
|
||||
printf_file($prev[2]);
|
||||
printf_duration($duration);
|
||||
|
||||
if( uc($cur[2]) eq "END" ){
|
||||
printf("# END label at %.6f\n",$cur[0]);
|
||||
# known bug in the demuxer:
|
||||
# the last slide name has to be repeated w/o duration
|
||||
printf_file($prev[2]);
|
||||
printf("# End of ffmpeg concat sequence produced by muxsa-al2fc\n");
|
||||
exit(0);
|
||||
}
|
||||
@prev = @cur;
|
||||
}
|
||||
|
||||
# we have reached the end of the input file without an explicit END label
|
||||
# ASSUME that the last slide should be shown for 1 sec
|
||||
printf("# EOF but no END label. ASSUMING a duration for the last slide.\n");
|
||||
printf_file($cur[2]);
|
||||
printf_duration(1.0);
|
||||
printf_file($cur[2]);
|
||||
|
||||
printf("# End of ffmpeg concat sequence produced by muxsa-al2fc\n");
|
||||
|
||||
############################################################################
|
224
bin/muxsa-kvm2png
Executable file
224
bin/muxsa-kvm2png
Executable file
@ -0,0 +1,224 @@
|
||||
#!/bin/bash
|
||||
|
||||
# muxsa-kvm2png
|
||||
#
|
||||
# part of muxsa, https://git-nks-public.tik.uni-stuttgart.de/edu/muxsa
|
||||
#
|
||||
# this script makes a series of screenshots from a KVM virtual machine
|
||||
# and saves them as PNG files. It will press the PgDown key after each
|
||||
# screenshot. Intended usage: dump a presentation (e.g., Powerpoint
|
||||
# running in a Windows VM) into a series of PNG files, for further
|
||||
# processing with the muxsa tool chain.
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Sebastian Kiesel <sebastian.kiesel@tik.uni-stuttgart.de>
|
||||
#
|
||||
# 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, sublicense,
|
||||
# and/or sell 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.
|
||||
|
||||
############################################################################
|
||||
|
||||
echo "This is muxsa-kvm2png."
|
||||
|
||||
# various parameters can be set as an environment variable (export XX="y z")
|
||||
# or can be set in our RC file. Otherwise we will assign default values below.
|
||||
|
||||
if [ -r "${HOME}/.muxsarc" ] ; then
|
||||
echo "Found ${HOME}/.muxsarc ... will source it."
|
||||
. "${HOME}/.muxsarc"
|
||||
fi
|
||||
|
||||
echo "Will work with these settings:"
|
||||
|
||||
echo "MUXSA_KVM2PNG_VM_NAME=${MUXSA_KVM2PNG_VM_NAME:="win10-office"}"
|
||||
echo "MUXSA_KVM2PNG_SIZE_X=${MUXSA_KVM2PNG_SIZE_X:="1920"}"
|
||||
echo "MUXSA_KVM2PNG_SIZE_Y=${MUXSA_KVM2PNG_SIZE_Y:="1080"}"
|
||||
echo "MUXSA_KVM2PNG_EXTRA_X=${MUXSA_KVM2PNG_EXTRA_X:="0"}"
|
||||
echo "MUXSA_KVM2PNG_EXTRA_Y=${MUXSA_KVM2PNG_EXTRA_Y:="0"}"
|
||||
echo "MUXSA_KVM2PNG_SLIDE_PREFIX=${MUXSA_KVM2PNG_SLIDE_PREFIX:=""}"
|
||||
echo "MUXSA_KVM2PNG_SLIDE_NUMBER_START=${MUXSA_KVM2PNG_SLIDE_NUMBER_START:="0"}"
|
||||
echo "MUXSA_KVM2PNG_SLIDE_NUMBER_END=${MUXSA_KVM2PNG_SLIDE_NUMBER_END:="9999"}"
|
||||
echo "MUXSA_KVM2PNG_FORCE_OVERWRITE=${MUXSA_KVM2PNG_FORCE_OVERWRITE:=""}"
|
||||
echo "MUXSA_KVM2PNG_BUGFIX_SHOOT_TWICE=${MUXSA_KVM2PNG_BUGFIX_SHOOT_TWICE:=""}"
|
||||
echo "MUXSA_KVM2PNG_SLEEP=${MUXSA_KVM2PNG_SLEEP:="3"}"
|
||||
echo "MUXSA_KVM2PNG_MD5_LAST_SLIDE=${MUXSA_KVM2PNG_MD5_LAST_SLIDE:="092eb68a91b4d2a73833f00a01dc5cb0"}"
|
||||
echo
|
||||
|
||||
############################################################################
|
||||
|
||||
TMP_FILE="$(mktemp -t muxsa-kvm2png-XXXXXXXXXX.ppm)"
|
||||
if [ ! -w "${TMP_FILE}" ] ; then
|
||||
echo "Error: cannot create tmp_file. abort."
|
||||
exit 1
|
||||
fi
|
||||
trap 'rm -f -- "${TMP_FILE}"' EXIT
|
||||
|
||||
############################################################################
|
||||
|
||||
muxsa-kvm2png-screenshot-to-tmp () {
|
||||
echo "muxsa-kvm2png: screenshot ${MUXSA_KVM2PNG_VM_NAME} ${TMP_FILE}"
|
||||
virsh -c qemu:///system "screenshot ${MUXSA_KVM2PNG_VM_NAME} ${TMP_FILE}"
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "muxsa-kvm2png: screenshot failed. abort."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# the first sceenshot after a resolution change is sometimes garbled
|
||||
# workaround: save it twice
|
||||
if [ "${MUXSA_KVM2PNG_BUGFIX_SHOOT_TWICE}" ] ; then
|
||||
virsh -c qemu:///system \
|
||||
"screenshot ${MUXSA_KVM2PNG_VM_NAME} ${TMP_FILE}"
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "muxsa-kvm2png: screenshot failed. abort."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# get the size in pixels of the screenshot we have taken
|
||||
# (needs identify from imagemagick), and ...
|
||||
TMP_SZ_X=$(identify -format "%w" "${TMP_FILE}")
|
||||
TMP_SZ_Y=$(identify -format "%h" "${TMP_FILE}")
|
||||
|
||||
# ... compare to desired size
|
||||
if [ ${TMP_SZ_X} -eq ${MUXSA_KVM2PNG_SIZE_X} -a \
|
||||
${TMP_SZ_Y} -eq ${MUXSA_KVM2PNG_SIZE_Y} ] ; then
|
||||
echo "Screenshot is ${TMP_SZ_X} x ${TMP_SZ_Y} - as desired. good."
|
||||
TMP_SZ_OK=1
|
||||
else
|
||||
echo "Warning: Screenshot is ${TMP_SZ_X} x ${TMP_SZ_Y} but desired"\
|
||||
"size is ${MUXSA_KVM2PNG_SIZE_X} x ${MUXSA_KVM2PNG_SIZE_Y} ."
|
||||
TMP_SZ_OK=""
|
||||
fi
|
||||
}
|
||||
|
||||
############################################################################
|
||||
|
||||
echo "Performing a test screenshot to check image size."
|
||||
muxsa-kvm2png-screenshot-to-tmp
|
||||
if [ ! "${TMP_SZ_OK}" ] ; then
|
||||
echo "We will try to adjust the size of the spicy window."
|
||||
case "$(read -p "Press q [return] to abort or [return] to continue: ")" in
|
||||
n|N|q|Q)
|
||||
echo "muxsa-kvm2png aborted."
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
xdotool search --class spicy windowsize %@ \
|
||||
$(( ${MUXSA_KVM2PNG_SIZE_X} + ${MUXSA_KVM2PNG_EXTRA_X} )) \
|
||||
$(( ${MUXSA_KVM2PNG_SIZE_Y} + ${MUXSA_KVM2PNG_EXTRA_Y} ))
|
||||
sleep 5
|
||||
echo "Performing another test screenshot to check image size."
|
||||
muxsa-kvm2png-screenshot-to-tmp
|
||||
if [ ! "${TMP_SZ_OK}" ] ; then
|
||||
echo "Screenshot still does not have the desired size in pixels."
|
||||
echo "Maybe, resizing the spicy window has failed."
|
||||
echo "Or maybe, you need to adjust MUXSA_KVM2PNG_EXTRA_X / _Y"
|
||||
# extra size accounts for menus of the spicy window.
|
||||
# if the desired size is larger than the actual size, that
|
||||
# difference has to be added to the current extra size
|
||||
echo "Current MUXSA_KVM2PNG_EXTRA_X value: ${MUXSA_KVM2PNG_EXTRA_X}"
|
||||
echo "Try: $(( ${MUXSA_KVM2PNG_SIZE_X} - ${TMP_SZ_X} + \
|
||||
${MUXSA_KVM2PNG_EXTRA_X} ))"
|
||||
echo "Current MUXSA_KVM2PNG_EXTRA_Y value: ${MUXSA_KVM2PNG_EXTRA_Y}"
|
||||
echo "Try: $(( ${MUXSA_KVM2PNG_SIZE_Y} - ${TMP_SZ_Y} + \
|
||||
${MUXSA_KVM2PNG_EXTRA_Y} ))"
|
||||
echo "You can set these as environment variables or in ~/.muxsarc"
|
||||
echo "muxsa-kvm2png aborted."
|
||||
exit 1;
|
||||
fi
|
||||
fi
|
||||
echo "Successfully took test screenshot with the right size."
|
||||
|
||||
############################################################################
|
||||
|
||||
cat <<EOF
|
||||
|
||||
This is muxsa-kvm2png.
|
||||
|
||||
Name of the virtual machine: ${MUXSA_KVM2PNG_VM_NAME}
|
||||
Screenshot size ${MUXSA_KVM2PNG_SIZE_X}x${MUXSA_KVM2PNG_SIZE_Y} verified.
|
||||
|
||||
Please press ... and return:
|
||||
|
||||
q to abort
|
||||
y to start taking screenshots
|
||||
f to send F5 to the virtual machine and start taking screenshots
|
||||
|
||||
EOF
|
||||
|
||||
case "$(read -t 10 -p "Answer: ")" in
|
||||
n|N|q|Q)
|
||||
echo "muxsa-kvm2png aborted."
|
||||
exit 1;
|
||||
;;
|
||||
y|Y)
|
||||
;;
|
||||
*)
|
||||
echo "Sending F5 to ${MUXSA_KVM2PNG_VM_NAME}"
|
||||
virsh -c qemu:///system "send-key ${MUXSA_KVM2PNG_VM_NAME} KEY_F5"
|
||||
sleep 3
|
||||
;;
|
||||
esac
|
||||
|
||||
############################################################################
|
||||
|
||||
SLIDE_NUMBER="${MUXSA_KVM2PNG_SLIDE_NUMBER_START:-0}"
|
||||
while true ; do
|
||||
|
||||
muxsa-kvm2png-screenshot-to-tmp
|
||||
if [ ! "${TMP_SZ_OK}" ] ; then
|
||||
echo "muxsa-kvm2png: screenshot failed. abort."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OUTFILE=$(printf "${MUXSA_KVM2PNG_SLIDE_PREFIX}%04i.png" ${SLIDE_NUMBER})
|
||||
SLIDE_NUMBER=$(($SLIDE_NUMBER+1))
|
||||
if [ -f "${OUTFILE}" -a ! "${MUXSA_KVM2PNG_FORCE_OVERWRITE}" ] ; then
|
||||
echo "Outfile ${OUTFILE} exists and overwriting not allowed. abort."
|
||||
exit 1
|
||||
fi
|
||||
echo "Converting and saving screenshot to ${OUTFILE}"
|
||||
pnmtopng -force "${TMP_FILE}" > "$OUTFILE"
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Converting and saving screenshot failed. abort."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${MUXSA_KVM2PNG_MD5_LAST_SLIDE}" ] ; then
|
||||
if md5sum "${OUTFILE}" | \
|
||||
grep -q "^${MUXSA_KVM2PNG_MD5_LAST_SLIDE}" ; then
|
||||
|
||||
echo "Screenshot's md5sum = MUXSA_KVM2PNG_MD5_LAST_SLIDE. end."
|
||||
break
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${SLIDE_NUMBER}" -gt "${MUXSA_KVM2PNG_SLIDE_NUMBER_END}" ] ; then
|
||||
echo "Maximum slide number reached. abort."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Sending PgDown and sleeping briefly"
|
||||
virsh -c qemu:///system "send-key ${MUXSA_KVM2PNG_VM_NAME} KEY_PAGEDOWN"
|
||||
sleep "${MUXSA_KVM2PNG_SLEEP}"
|
||||
|
||||
done
|
||||
echo "muxsa-kvm2png finished successfully!"
|
||||
|
||||
############################################################################
|
78
bin/muxsa-pngaac2mp4
Executable file
78
bin/muxsa-pngaac2mp4
Executable file
@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
|
||||
# muxsa-pngaac2mp4
|
||||
#
|
||||
# part of muxsa, https://git-nks-public.tik.uni-stuttgart.de/edu/muxsa
|
||||
#
|
||||
# this script tells ffmpeg (https://ffmpeg.org/) to read
|
||||
# a series of slides in png file format (created with muxsa-kvm2png),
|
||||
# a soundtrack.aac (recorded with audacity), and
|
||||
# a ffmpeg concat multiplexer sequence file (created with muxsa-al2fc)
|
||||
# and multiplex everything together
|
||||
# into a mp4 video of the slideshow with background narration
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Sebastian Kiesel <sebastian.kiesel@tik.uni-stuttgart.de>
|
||||
#
|
||||
# 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, sublicense,
|
||||
# and/or sell 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.
|
||||
|
||||
############################################################################
|
||||
# see https://trac.ffmpeg.org/wiki/Slideshow
|
||||
|
||||
echo "This is muxsa-pngaac2mp4."
|
||||
|
||||
OUTFILE="out.mp4"
|
||||
if [ "$1" ] ; then
|
||||
OUTFILE="$1"
|
||||
# make sure that file ends on .mp4
|
||||
OUTFILE="${OUTFILE%%.mp4}.mp4"
|
||||
fi
|
||||
|
||||
if [ ! -f slides.concat ] ; then
|
||||
echo "error: file slides.concat missing. abort."
|
||||
echo "consider using muxsa-al2fc for creating one."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f soundtrack.m4a ] ; then
|
||||
AUDIOFILE="-i soundtrack.m4a"
|
||||
AUDIOOPTS="-c:a copy"
|
||||
else
|
||||
if [ -f soundtrack.wav ] ; then
|
||||
AUDIOFILE="-i soundtrack.wav"
|
||||
AUDIOOPTS="-c:a aac -b:a 128k"
|
||||
else
|
||||
if [ -f audio.concat ] ; then
|
||||
AUDIOFILE="-f concat -i audio.concat"
|
||||
AUDIOOPTS="-c:a aac -b:a 128k"
|
||||
else
|
||||
echo "neither soundtrack.m4a, .wav, nor audio.concat found. abort."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
ffmpeg -f concat -i slides.concat ${AUDIOFILE} \
|
||||
-vsync cfr -vf fps=25 \
|
||||
-c:v libx264 -preset slow -tune stillimage -crf 23 -pix_fmt yuv420p \
|
||||
${AUDIOOPTS} \
|
||||
-movflags +faststart -brand mp42 "${OUTFILE}"
|
||||
|
||||
############################################################################
|
BIN
doc/muxsa-blockdiagram.png
Normal file
BIN
doc/muxsa-blockdiagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 149 KiB |
Loading…
Reference in New Issue
Block a user