Recording

Canon HV20 HDV camcorder. 25p Cinema Mode, CINE colors. 60 min miniDV-tapes. RØDE Stereo VideoMic.

Capturing

Linux DVGrab: sudo dvgrab -f hdv -s 0

or Windows HDVSplit

Decoding

Windows DGIndex/DGMPGDec: .m2t → .d2v + .mp2

Windows BeSweet: .mp2 → .wav, besweet -core( -input "lec1-a PID 814 L2 2ch 48 384 DELAY 0ms.mp2" -output "lec1-a-orig.wav" -2ch ) -azid( -n1 -c normal -L -3db --maximize ) -ota( -d 0 )

Linux/Mac/Windows Audacity: occasionally used for removing loud noises, 50 Hz hum (+ harmonics), etc.

Linux/Mac/Windows SoX: 48 KHz → 44.1 KHz, sox -V3 -S -v 1.2 lec1-a-nohum.wav -b 16 lec1-a.wav rate -v 44100 dither (otherwise Flash will convert to 44.1 KHz internally)

Editing

Windows AviSynth: lec1.avs (Notepad++)

v1 = MPEG2Source("lec1-a.d2v").LanczosResize(512, 288)   # occasionally added some cropping too, or conversion YV12->RGB for debugging
a1 = WavSource("lec1-a.wav")
va = AudioDub(v1,a1)
va = Trim(va,5,va.framecount-5)  # trim a few frames as they might be silent depending on camera (evident in some crossfades)
v2 = MPEG2Source("lec1-b.d2v").LanczosResize(512, 288)
a2 = WavSource("lec1-b.wav")
vb = AudioDub(v2,a2)
vb = Trim(vb,5,vb.framecount-5)

va = Trim(va,150,0)
vao = Trim(va,0,va.framecount-10-25)
fadea = Trim(va,va.framecount-9-25,0)
vbo = Trim(vb,10+25,0)
fadeb = Trim(vb,0,9+25)
fade = Dissolve(fadea, fadeb, 5) \
  .Subtitle("Kasetinvaihto", x=408, y=268, spc=10, font="calibri", size=16, text_color=color_white, halo_color=color_black)
mov = vao + fade + vbo
mov = Trim(mov,0,147945)
img = ImageSource("cybernetics-logo.png", end = 300, fps = 25, use_DevIL=true, pixel_type = "RGB32")
mov1 = Trim(mov,0,141).FadeIn(40,color_white) \
	.Subtitle("Professori Heikki Hyotyniemi", x=8, y=190, spc=10, font="calibri", size=22, text_color=color_white, halo_color=color_black) \
	.Subtitle("AS-74.4192 Kybernetiikan alkeet", x=8, y=210, spc=10, font="calibri", size=19, text_color=color_white, halo_color=color_black) \
	.Subtitle("4. luento: Neocybernetic Basic Models", x=8, y=239, spc=10, font="calibri", size=16, text_color=color_white, halo_color=color_black) \
	.Subtitle("Teknillinen korkeakoulu 13.2.2009", x=8, y=254, spc=10, font="calibri", size=16, text_color=color_white, halo_color=color_black) \
	.Subtitle("Katso myos muu luentomateriaali verkosta", x=8, y=268, spc=10, font="calibri", size=16, text_color=color_white, halo_color=color_black) \
	.Overlay(img, x=292, y=185, mask=img.ShowAlpha(), mode="multiply", opacity=1)
mov2 = Trim(mov,137,0)
Dissolve(mov1, mov2, 5).FadeOut(20,color_white)

ColorMatrix(mode="Rec.709->Rec.601", clamp=0, inputfr=false, outputfr=true)   # conversion from HD color space and expansion to full range [0-255]

#SoundOut()  # uncomment to export sound

Windows VirtualDub: check timings of .avs (frameserved on the fly from original .m2t), edit script as needed and export final .wav

Linux/Mac/Windows Inkscape and Gimp: for editing vector and bitmap graphics when needed

Encoding

Linux/Mac/Windows x264: x264 --crf 22 --subme 6 --ref 4 --bframes 3 --b-adapt 2 --direct auto --deblock -1,-1 --aq-mode 1 --mixed-refs --weightb --8x8dct --partitions p8x8,b8x8,i4x4,p4x4 --level 3.1 --no-psnr --no-ssim --threads auto --thread-input --progress --me umh --trellis 2 --fullrange off --colormatrix smpte170m --transfer smpte170m --colorprim smpte170m -o lec1.x264 lec1.avs (increase crf to aim for lower quality and bitrate) (Currently Flash can display only BT.601 colors (no BT.709 as in HD), so equivalent smpte170m is a hint for other players. Unlike many other players, Flash respects fullrange flag, and the source here indeed is full range [0-255], but depending on the player input and on the graphics pipeline output the range may be shrink or cut in various ways in different configurations, resulting in washed-out image, so after experimentation cheating the flag for maintaining constrast in Flash seemed the best compromise for Flash and desktop players, still keeping the dynamic range in the bitstream.)

Linux/Windows Nero AAC Encoder: neroAacEnc -br 64000 -he -2pass -if lec1.wav -of lec1.mp4

Linux/Mac/Windows MP4Box: MP4Box -add "lec1.x264#video:fps=25" "lec1.m4v"
MP4Box -add "lec1.mp4#audio" "lec1.m4v"
MP4Box -inter 500 -itags album="AS-74.4192 Elementary Cybernetics, Spring 2009, Helsinki University of Technology":artist="Prof. Heikki Hyotyniemi":album_artist="Prof. Heikki Hyotyniemi":tracknum="4/12":track="Lecture 4: Neocybernetic Basic Models, 13.2.2009":comment="Video by Petri Lievonen":created="2009":name="Lecture 4: Neocybernetic Basic Models, 13.2.2009" -lang Finnish "lec4.m4v"

Windows Adobe Acrobat: lecture slides .ppt → .pdf (this and the next step could be substituted by Open Office Impress)

Linux SWFTools: .pdf → .swf, pdf2swf -z -B slideviewer.swf -s flashversion=9 lec1.pdf -o lec1.swf
slideviewer.sc scripted with SWFC:

.flash filename=slideviewer.swf version=8 background=white bbox=778x538
    .edittext info text="" color=gray size=100% width=30 height=30 align=center border=none noselect variable=infoText
    .sprite viewport
        # movie here
    .end
    .put viewport
    .put info x=-8 y=510 alpha=50% scale=150%
    .action:
        _root.viewport.stop();
        _root.info.embedFonts = 0;
        waitouches = new Object();
        waitouches.onKeyDown = function () {
            keydownrun=true;
            _root.kd=Key.getCode();
            switch(Key.getCode()) {
                case 40: //Key.DOWN:
                         _root.viewport.nextFrame();
                        break;
                case 38: //Key.UP:
                         _root.viewport.prevFrame();
                        break;
                case 33: //Page prente:
                         _root.viewport.prevFrame();
                        break;
                case 34: //Page suivante:
                         _root.viewport.nextFrame();
                        break;
                case 35: //Key.End:
                        _root.viewport.gotoAndStop(_root.viewport._totalframes);
                        break;
                case 36: //Key.Home:
                         _root.viewport.gotoAndStop(1);
                        break;
                case 37: //Key.Left:
                         _root.viewport.prevFrame();
                        break;
                case 39: //Key.Right:
                         _root.viewport.nextFrame();
                        break;
                }
            _root.infoText = String(_root.viewport._currentframe);
            updateAfterEvent();
        };
        waitouches.onMouseDown = function () {
            if (_root._xmouse < 389) {
                _root.viewport.prevFrame();
                updateAfterEvent();
            } else {
                _root.viewport.nextFrame();
                updateAfterEvent();
            };
            _root.infoText = String(_root.viewport._currentframe);
        };
        Key.addListener(waitouches);
        Mouse.addListener(waitouches);
    .end
.end 

Publishing

Upload the encoded files to a server and modify html: an example

Remember to check that the webserver serves the proper content type with wget -S: add to .htaccess AddType video/mp4 .m4v

Adobe Flash JW FLV Player (or alternatively use FlowPlayer)

Some JavaScript libraries used: SWFObject, jQuery, (PDFObject replaced with PDF2SWF)

Subtitling

Windows SoX: slowing audio to half speed for transcription, sox.exe -V3 -S lec2.wav lec2-slow.wav tempo 0.5 30

Timed Text (W3C)

Experimented with speech recognition

Google Translate

Subtitling tools forthcoming...