[Home]

Table of contents


Technical details

Overview

The creation of a video proceeds in three stages. The first is the preprocessing, where I create the props (images and animations that will be overlaid on top of the main video). The shooting is done in the second stage. The third stage puts everything together.

Preprocessing

Other than the overall planning of the topic, the main effort in this stage is devoted to creating the props: images and animations. The animations themselves start out their lives as a sequence of images. All the images (whether part of such a sequnce or not) are finally produced by inkscape. Ocassionally, I need to import supporting materials created by Art Of Illusion or R. The steps are:

Shooting

For shooting I start my Overlay app, select the folder, start the camera, do OK syncing, and start speaking. Holding the camera with my right hand at an arm's length is particularly convenient for advancing through the images with my index finger unseen by the camera. Also, my left hand is free for gesturing. However, this is somewhat tiring for the right hand, and is unsuitable for shoots longer than 5 minutes or so. For the longer shoots I hold the camera with my left hand, and use the right hand to both gesture and advance.

Staring into the camera is not a good idea, as this makes my eyes look abnormally squinted. If I look at the visuals, then I indeed appear to be looking at the visuals during the video. This is an unplanned bonus. When I am not looking at the visuals, I prefer to look away casually with only occasional glances at the camera. I generally walk at a leisurely pace during the shoot.

Everytime I move to a new topic, I change my location. I shoot the location for a few seconds both as an establishing shot, as well as a restful prelude.

This stage produces two types of output: the recorded videos and a cue.txt file in each topic folder inside the transfer folder.

If we need a screencast, then we use kazam. This produces a third type of output: a screencast mp4 file.

Postprocessing

This stage starts with transfering the output of the shooting stage into the laptop. All the videos are stored inside the vid folder, and the cue.txt files are to be copied to the appropriate topic folders. This latter job is facilitate by the docue <lecture number> command (to be issued from inside (a copy of) the transfer folder of my phone.

Now we need to run the command doamelt from inside the lecture folder. This will create an mlt forlder under the lecture folder, and populate with mlt files based on the cue.txt files in each topic folder. If there is some animation, then I need to modify the appropriate cue.txt file by adding the triple "<png root> <start number> <end number" to the line after where the animation is to be inserted.

Next it is time to launch kdenlive and load the template file. We import the vid and the mlt folder. Typically, I shoot the videos in order (including the estbalishing shots). So I can drag and drop all the videos on the timeline in order. Then I add the mlt files and sync them. After that I edit off the initial and final parts of each. Then I add the separators and trim the estbalishing shots. Finally, I add the separator slides and render the movie to webm format. Then outside kdenlive I apply dosanxep to compress the rendered video.

Scripts used

domakelec

if [ ! $# == 1 ]; then
  echo "Usage: domakelec <n>"
  exit -1
fi
echo "Creating lec$1"
mkdir lec$1
cd lec$1
pwd
mkdir vid
cp $c/template.kdenlive lec$1.kdenlive


doanim

if [  $# != 3 ]; then
  echo "Usage: doanim <svg root> <png root> <nframe>"
  echo "There should be a file <svg root>1.svg in the working directory."
  echo "It should have reference to <png root>0001.png in it."
  echo "This program will create <svg root><i>.svg for i from 1 to <nframe>."
  echo "<svg root><i>.svg is same as <svg root>1.svg except that"
  echo "the references to <png root>0001.png will be changed to "
  echo "<png root><j>.png, where j is i 0-padded up to 4 digits."
  exit 1
fi
for((i=2;i<=$3;i++)); do
   echo $i
   printf -v j "%04g" $i
   sed -r "s/${2}0001/$2$j/g" ${1}1.svg > $1$i.svg
done

doandro

echo $v
java -classpath ~/na/v/android AndroViewer $*
Here we are using the AndroViewer.java program.

docue

folder="lec$1"
echo "Folder is [$folder]"

declare -a fldextlist
mapfile fldextlist < $c/$folder/order.txt

i=0
for fldext in ${fldextlist[*]} ; do
   fld="${fldext%,*}"
   i=$((i+1))
   echo "$i --> $c/$folder/$fld/"
   cp $i/cue.txt $c/$folder/$fld/
done

doamelt

if [ ! -e order.txt ]; then
  echo "No order.txt here!"
  exit 1
fi


declare -a fldextlist
mapfile fldextlist < order.txt

if [ ! -e mlt ]; then
  mkdir mlt
fi
rm mlt/*.mlt

for fldext in ${fldextlist[*]} ; do
   fld="${fldext%,*}"
   java -classpath ~/na/v/android Melter $fld
   mv $fld.mlt mlt/
done
This script uses the Melter.java program.

ipall

if [ ! -e order.txt ]; then
  echo Error: No order.txt here.
  exit 1
fi

declare -a fldextlist
mapfile fldextlist < order.txt

for fldext in ${fldextlist[*]} ; do
   fld="${fldext%,*}"
   ext="${fldext#*,}"
   echo Folder=$fld , Ext=$ext
   
   cd $fld

   for f in *.svg; do
     extension="${f##*.}"
     filename="${f%.*}"
     echo -n "$f -> $filename.png : "
     if [ ! -e $filename.png ] | [ $f -nt $filename.png ]; then
        echo "Converting."
        inkscape -h 480 $f -e $filename.png
     else
        echo "Already done."
     fi
   done

   if [ $# == 1 ]; then
      echo Creating index.txt
      ls -1 $ext[0-9].png > index.txt
      more index.txt
   fi

   cd ..
done

dosanxep

ffmpeg -i $1.webm -vcodec libx265 -crf 28 -strict -2 $1.mp4

An R script for producing animation

This script creates an animation (in the form of an image sequence) building up some diagram. It consists of the process function, and some supporting routines.

md = function(x) if(!dir.exists(x)) dir.create(x)

scrn = function(xlo, xhi, ylo, yhi,...) {
    bareplot(0,xlim=c(xlo,xhi),ylim=c(ylo,yhi),ty='n',...)
}

spStart = function(fname) {
    png(fname,width=640)#,bg='transparent')
}

spEnd = function() dev.off()


process = function(xs,xe,ys,ye,rt,fun, nf, dur=1, ps=0, pe=0, ...) {
    md(rt)
    spStart(paste(rt,'/pic%04d.png',sep=''))
    filename = sprintf('%s.lst',rt)
    cat("FPS",nf,"\n",file=filename)
    for(i in 1:nf) {
      scrn(xs,xe,ys,ye,...) 
      pnow = ps + (i-1)/(nf-1)*(pe-ps)
      fun(i,pnow) # i is the frame number (int, so exact), 
                  # pnow is param value (may be approx)

      cat(sprintf('%s/pic%04d.png\n',rt,i),file=filename,append=TRUE)
    }
    spEnd()
}
The following code uses this script:
###-----------------------
genDat = function(mn,sd) {
    x = rnorm(10,sd=sd)
    x - mean(x) + mn
}

x1 = genDat(0,0.2)
x2 = genDat(1,0.2)
x3 = genDat(2,0.2)
xall = c(x1,x2,x3)

y1 = genDat(0,2)
y2 = genDat(1,2)
y3 = genDat(2,2)
yall = c(y1,y2,y3)

plot(c(x1,x2,x3),c(y1,y2,y3))
zr = rep(0,30)
clr = c(rep('red',10),rep('blue',10),rep('green',10))

f = function(i,t) {
    abline(h=0,lwd=3)
    points((1-t)*xall+t*yall,zr,col=clr,pch=20,cex=3)
}

process(min(yall),max(yall), 'test', 0,1,f,30,-0.2, 0.2 )