June 1, 2017

Capturing and restoring video from VHS tapes losslessly

Filed under: Technical — Tags: , , , , — James Bunton @ 12:00 am

Back in the 1990s my family recorded some home videos using a VHS camera. It’s pretty hard to play these on modern equipment, so back in 2013 I digitised them all.

Of course when using an analogue source like tape it’s not really possible to do a lossless copy. However I wanted to do the highest quality capture with the equipment available to me, and I wanted to be able to redo post-processing in the future in case I have the time, motivation and technology to improve things further.


  • Transfer from VHS tape to computer.
  • Retain lossless master so I could redo post-processing and encoding in the future.
  • Compact h264/mp4 version for distribution to family.
  • Volume normalisation.
  • Colour correction.
  • Script to easily rerun post-processing on lossless master and regenerate mp4.

Lossless capture

You’ll need an analogue video capture card and a sound card with analogue audio inputs. I have an Avermedia capture card using the SAA7130 chipset, however any V4L2 capture card should work.

You should connect your VCR to the capture card using S-Video if possible, otherwise use the composite video (yellow RCA) connector. Connect the audio out of your VCR to your soundcard.

Test the playback using v4l-play. Capture a lossless video file using v4l-rip. This will produce a very large AVI file which uses lossless PCM audio and the lossless FFV1 video codec.

Shrink videos by encoding to H.264 in the mp4 container

If you’re happy with the video quality as-is you can use HandBrake to encode them right away. I recommend using the MP4 container with H.264/AAC. This is a common standard and will likely last for a long time. Note that this format is lossy, so you should keep that large AVI around just in case you want to re-encode or do other post-processing in the future.

You’ll want to crop at least 16 pixels from each edge and apply a deinterlacing filter.

Read on for details of the post-processing that I performed on my videos.

Postprocessing – scene splitting, improved picture and audio quality

Many scenes on the same tape were recorded at very different times. I wanted to cut these into smaller video files so I could date and name them individually.

I used the avidemux GUI to find the exact frame numbers where I wanted to split the video file. This was quite a painstaking process, going through many hours of footage to select the start and end frame numbers for each scene, then figuring out the approximate dates and choosing a name.

I can’t tell whether it was due to degradation from the VHS tape medium or just because that old camera was never any good, but the colour in many of the videos was all wrong. Frequently everything appeared blue, this was really ugly! I wanted to fix this by selecting something in the picture which was supposed to be white and having the rest of the colours be adjusted to match.

I had lots of disk and CPU to throw at all these problems, so I did that. I wrote a short Python script, video-transform, which does the following:

  • Reads an input frames.txt file with video source filenames, scene start/end frame numbers and an optional white colour to use in colour correction.
  • Use mplayer to dump each frame of the video source file to a lossless PNG.
  • Extract the full audio data to a WAVE file.
  • Use ImageMagick to apply a colour correction matrix to the image frames for each scene.
  • Use SOX to extract the audio for each scene and apply volume normalisation.
  • Use mencoder to encode the images into lossless FFV1 again and to mux with the scene audio file.

Run the video-transform script

$ video-transform frames.txt source_dir dest_dir tmp_dir
# frames.txt file
source tape1.avi
dest scene1 - some things happen.avi
crop 1002-4987

source tape1.avi
dest scene2 - some more things happen.avi
crop 4991-5678
whitecolor b0d8ff

You must ensure that the source files are present in the source_dir specified on the command line. The output files will be created in the dest_dir. You should ensure tmp_dir is on a filesystem with ~50-100GiB of free space. Huge numbers of temporary files will be created there.

Once you’re done you can transcode the resulting AVI files using HandBrake. Be sure to crop them and enable the deinterlacer!