Thursday, September 8, 2011

Screencasting and Video Production with FOSS

The following procedures were painfully discovered through trial and error, extensive research, and a few accidents. Most of this information can be found online in various forms. However, I thought it would be helpful to aggregate it into a cohesive process. I developed this document originally after spending quite a bit of time trying to figure out how to demonstrate some technical software and deliver it in a repeatable format. I've since used these methods to edit personal home videos, gameplay footage, and other technical screencasts.

The most recent video I posted is here:
Edit: The original video I created with this method:

This video is a perfect example of the use of all tools mentioned in this post. My intention was to use completely free and open source software, nearly all of which is available cross-platform. I will go into more detail and mention alternatives when available. If there is interest for more detail I can follow-up with additional posts. The process overview I use is as follows:
  1. Record Video Without Sound (recordMyDesktop)
  2. Convert Video to Individual Frames (mplayer, Blender)
  3. Create Graphics for Scene Transitions (Inkscape, GIMP)
  4. Edit Frames as Video, adding Transition (Blender)
  5. Record Sound to Final Video Cut (Audacity)
  6. Combine Video and Audio and Edit (Blender)
  7. Render to Final Video (Blender)
  8. Convert if needed (ffmpeg)
This is assuming an entire screencast or video is the intended result. Certainly specific sections of this may apply to what you are doing.

Record Video Without Sound
Software: recordMyDesktop
Platforms: Linux
Alternatives: gnome-shell, ffmpeg,

Most screen capturing software has the ability to also record sound. However, I have found it best to record the raw video first, then edit this down with transitions before recording audio. This allows lengthy operations to be skipped or sped up with transitions, or even allows for a completely different person to provide audio at a later time. I also like the ability to remove any background sounds such as keyboard typing or mouse clicks, but that is just a personal preference. In general I like this approach because the video can be recorded in a sort of unprepared manner and fixed in editing before even worrying about voice-over audio. Later, I prefer to take the edited video and play it as I write down a rough script that I can then record my voice-over onto.

There are many great tutorials on using recordMyDesktop, so I won't rehash those here. These are some quick tips I've found to work for me:
  • Disable Sound
  • Use 30 Frames Per Second
  • Full Shots Every Frame
  • Record in a standard resolution window rather than fullscreen
  • Remove any visible indications that time has passed such as the a clock display, in case actions need to be sped up
  • Use keyboard shortcuts (ctrl+alt+p to pause/resume, ctrl+alt+s to stop) instead of the mouse, as this will be distracting if you pause a lot
  • I found it better to simply restart any actions if I made a mistake and fix it in editing, rather than trying to re-record it in one perfect try
  • When typing in text commands, wait a few seconds before hitting Enter to allow the viewer to absorb the command - it is much easier to cut out extra seconds than to try and extend a scene
  • Clear a terminal and start over if it gets too cluttered
  • When showing User Interface actions, use deliberate mouse movements instead of keyboard shortcuts to visually relay what is happening
  • Consider recording applications in full-screen to block out any irrelevant or distracting components
  • Minimize any latency between the recording desktop and any remote equipment used - e.g. use a VM in a remote lab rather than recording locally and then connecting to remote equipment, limiting the number of frames that appear torn/broken from any latency

Convert Video to Individual Frames
Software: mplayer
Platforms: Linux, also available for Windows, OS X
Alternatives: Blender (render to images)

If recordMyDesktop was used, the videos will be .ogv files. In my experience, and from many other posts I've seen online, it is best to convert these into individual frame images first. The reason is that editing encoded video can be very unpredictable. The simplest way to accomplish this is to use mplayer. Thanks to Richard W. M. Jones for pointing me to his procedure on this. Previously I was using Blender to render the ogv movies to images, but running a loop against all your videos is far less work. The basic command syntax is:
$ mplayer ${video} -vo png:z=9:outdir=${directory}
If you have several videos, loop through them as such:
$ for video in $(ls *.ogv); do output=$(echo ${video} | awk -F "." '{print $1}'); mplayer ${video} -vo png:z=9:outdir=${output}; done

When complete, there should be several directories filled with PNG images.

Create Graphics for Scene Transitions
Software: Inkscape
Platforms:  Linux, Windows, OS X
Alternatives: GIMP, LibreOffice Draw

This is optional, but can add a very nice touch to videos. Create graphics that can be used for intros for sections, or to display any technical diagrams. Inkscape is by far the best tool for this, but can take a bit of learning.

Edit Frames as Video, adding Transitions
Software: Blender
Platforms: Linux, Windows, OS X
Alternatives: OpenShot

I have not yet had a chance to use OpenShot, but it look very promising. The interesting thing is that it requires Inkscape and Blender to be installed. I have become intimately familiar with Blender, so this is what I would recommend. Blender has a "Video Sequence Editor" feature that is very powerful, but seems to be not well known.

I must preface this section by saying that if you have never used Blender, it is unlike any other software you have encountered. You WILL NOT be able to launch the UI and poke around to figure things out. If you do this, you will hate life. Do not do this. Spend a few minutes watching this excellent basic navigation tutorial:

If you want to create 3D text, watch this:

This second video does not apply to the Blender Video Sequence Editor, but if you want to create 3D text titles, you need to be familiar with how to manipulate objects in Blender's 3D space. It is also possible to do 3D scene transitions (think video overlayed on a 3D cube that can rotate away while another scene rotates in), but I will leave that for another post.

Be sure to grab the latest Blender 2.59. If you are running Fedora, you will not want the version from the repos which is way old at 2.49b and does not have ffmpeg support. Just crab the latest stable from Blender's site and unpack it somewhere and run it. No compiling necessary.

There is too much to cover in this post, so I will just list some quick tips for video editing Blender:
  • Open Blender and switch to the Video Sequence Editor lay-out at the top, next to the Info Menu (File, Edit, etc) select the first box and choose "Video Editor"
  • Select "Add" (or shift+a) in the main Video Editor window
  • Select "Image" and browse to the image frames created earlier
  • Press "a" to select all images
  • Blender will create a movie single strip containing all these images
  • Edit the video as desired with the following controls:
    •  right-click will select a strip
    • shift+right-click selects/deselects multiple strips
    • right-click + drag on a strip to move it
    • mouse scroll to zoom
    • middle-mouse to move around editing canvass (shift and control modify)
    • x = delete strip
    • g = grab and initiate moving a strip (similar to right-click drag)
    • k = kit strip at cursor
    • shift+D = duplicate strip
    • b = box select
    • a = select/deselect all
    • shift+A = add item to editor
    • If you right-click on the very edge of a strip (left/beginning or right/end the arrow turns a different color) and drag, this actually crops/extends the video as much as you drag. In reality it is still there, think of it as "rolling it up", because at any time you can recover it by dragging back out
    • Review the video by hitting "play" (or alt+a)
If you drop two strips right next to each other, Blender will automatically re-align them to be contiguous. This is great if the two strips are the same scene and will appear to be completely smooth. However, if you need to transition from one scene to another, this can cause an abrupt change in scene. Instead, use various transition effects. If you notice all the way to the left in the editor there is a numbering scheme incrementing starting from 0. These are called "channels". Strips and transitions can be on any channel. When rendered it does not matter which channel a strip or transition is on. However, higher numbered channels take priority. So if you have a strip on channel 0 and drop another above it on channel 1, the video strip on channel 0 will not be seen if they overlap. Instead, you can offset the one on channel 1 and create a transition:
  1. Start by placing a strip on a channel
  2. Place the next strip on a channel higher than the original and overlap them by a few frames (depends on how long you want the transition)
  3. Right-click on the first strip, then Shift+Right-click on the second strip. This order is important, it is setting the order of the transition
  4. Now click on "Add, Effect Strip" and choose an effect. Gamma cross is good for a fade, add/subtract are good when you want to combine/remove elements. For example, several still images can be added together and have different elements fade in or out (this is where images created by Inkscape are very handy)
  5. You can also add a "Color" effect, which allow you to fade to and from a color such as black. This is good for transitioning smoothly between scenes
  6. Use graphics created from Inkscape or GIMP to introduce new sections

Record Sound to Final Video Cut
Software: Audacity
Platforms: Linux, Windows, OS X

Once your video is edited just the way you want it, play it back and note the time. It may be better to render out a video-only version and use a media player such as VLC (see the section below on Render to Final Video). Make any adjustments as needed. When satisfied with the length, play it back and take note of time cues and write a script of what you will say and at what point. Depending on your personal style, it may benefit you to write the entire script and practice several times while playing the video to make sure the timing is right. However, I found it better to simply review the video to determine how long a topic should be, then talk off the top of my head so it sounds more natural. As with video recording, shorter segments are more manageable, requiring less retries if any mistakes are made. In almost all cases, I've had to re-edit my video after adding my audio when I discover certain parts require more or less time.

As with the video recording, don't try to be perfect. It is far easier to simply keep talking and repeat something that you may have stumbled on, then edit it out in Blender later. Audacity is great for this task. Make sure to remove background noise after recording your audio. First select a background-only sound segment and choose "Effect, Noise Removal" and select "Get Profile". Next select all your sound with ctrl+a and choose "Effect, Noise Removal" again, and this time "Remove Noise". Doing this will minimize any popping sounds or fluctuations in background when going from the recorded audio to silence. Export the audio track to a lossless format such as FLAC or PCM WAV. This will be converted during the final render later.

Combine Video and Audio and Edit
Return to Blender and add the audio with "Add, Sound". Manipulate strips just as you would video strips, "k"to kut them, etc. There are advanced things you can do such as raising and lowering volume, mostly useful for fading music backgrounds if so desired, but I haven't done a lot of this yet.

If you find a location that you feel needs more video time to match the audio, add a still image of the video at that location and stretch it as needed. First, move to the location in the scene that you want to stretch. Click on the strip and note the image file name (default lower right window). Then add an image "Add, Image" and browse to that specific still. Now you can stretch this image to fill in the time as needed. The reason you cannot do this with the movie strip, is that it will "unroll" the frames and not stretch the still image as intended.

Render to Final Video
Once completely satisfied with the project, open the "Properties" window (or change screen lay-out to "Animation" and it will be in the lower right). There are many resources online that discuss the various options for rendering, but here are some settings that work for me:
  • Change the "Resolution" to match that of your video
  • Change the "Frame Rate" setting to match that of your video (or adjust as needed, trial and error)
  • Under "Output":
    • Select a filename and directory
    • Change "File Format" (default is PNG) to a video format, depending on your intended consumers
    • If applicable, change "Encoding" as needed (use presets as a guide)
  • Ogg/Theora/Vorbis works great, but I generally had more success using H.264/MPEG-4/H.264, especially if intending to upload to YouTube
If you will be rendering a lot or trying out different settings, it may be worth investigating rendering from the CLI. Just run --help against blender and play with the options.

Convert if needed

ffmpeg is great for manipulating the final video as needed. I generally didn't need to do this as I could just re-render from Blender, but YMMV. If you had issues creating an Ogg but desired one, ffmpeg2theora works great.

I hope this has been helpful and not to overwhelming. I think OpenShot looks like a good alternative to some of these steps, but I just haven't had time to play with it. It probably took me a good month to go from knowing nothing about video editing or Blender to creating videos. I handed a rough version of this document to a friend who was able to ramp up in just a couple of weeks. By far the largest learning curve here is Blender, but well worth the investment. 


Sunday, April 11, 2010

Automating batch video transcoding

I would like to share a script I wrote to automate batch transcoding of raw video files. I wrote this with DVDs in mind, but I'm sure it could be adapted for other sources.

For a few years now I've been backing up in my DVDs. It all began with my first daughter. We started building a library of movies for her, and quickly learned how much she enjoyed rubbing them on any rough surface, usually rendering them useless. Having paid full prices for re-re-re-releases of Disney and other titles, we were not excited about re-purchasing them. Not to mention we had to keep a variety of movies in our vehicle, as to not make her watch the same movie 10 times in a row, so it would be a shame to lose the pack of original DVDs.

I'm not going to talk about decrypting DVDs. The law is nebulous here, but in the end, I am backing up my own DVDs for reasons listed above. There are several good software solutions to decrypt your DVDs, I use AnyDVD since in the hundreds of DVDs I've used, only one failed. However, MacTheRipper and others for Linux also work.

The idea here is that I ripped all my DVDs and put them in a single sub-directory. Then I run the following script. It traverses all subdirectories, and transcodes them using HandBrake into mkv/mp4 file formats using H.264 and AAC. The end result is a video file that is around 600-900MB and can be streamed to PS3/Xb0x, or played on iPhone and TiVos, and of course by media players like VLC.

I originally wrote this in bash, but found there were times I wanted to run this from Windows or Mac, so I ported it to Python. It will handle any movies which were ripped and contain 1 or more titles. It looks for directories with "video_ts" subdirectories - usually DVD rips.

If only 1 title is found, the file name is the same as the directory name (e.g. Transfromers becomes Transformers.m4v). However, if there are several titles such as the main movie plus several extras, it appends "t#" to it (e.g. Transformers-t1.m4v, Transformers-t2.m4v, t3, t4, etc).

Currently HandBrake is called first to scan the directory, and the # of titles is discovered. Then HandBrake is called to transcode. If you would like to change the transcoder, edit the script, and also change the TRANSCODER_OPTIONS.

At the end, I print some stats such as # of movies transcoded, total time spent scanning, total time transcoding, and average time for each. If you run with --verbose, you will get output from handbrake such as frames per second.

Good luck, and please let me know if this is useful, or what I can change.

Sample usage:
[vinny ~]$ ./ -i videos/input/ -o videos/output/

Removed code from here and created a project at gitorious:

Added the ability to read ISOs instead of directories with --isos
Also added a wiki with some details: