VHS Capture on Linux

It has become increasingly apparent that VHS Tapes that inherently fragile, prone to mold, and urgently require capturing to a digital file format.


  • Although I was really impressed with the deinterlacing of QTGMC, I want to avoid using AviSynth as it is a Windows only package and I found it difficult to install and use. I would prefer to use FFMPEG for this instead.
  • Produce two video files: one being a ‘raw’ copy of the VHS tape in the interlaced format, and the other being a deinterlaced, upscaled, and cleaned up MP4 for normal use.
  • To produce a workflow that gives ‘good enough’ results. I’m not aiming to go overly high end but I would like an output which can hold up on a modern TV.
  • Keep things as simple and repeatable as possible. I don’t really want to spend loads of time tweaking clips and processes to get satisfactory results.

VHS Capture Flow


VCR - JVC HR-S9500

DVD Recorder (for Passthrough) - Panasonic DMR-E50

USB Capture Device - Hauppauge USB-Live2

The ideal VCR to use for this project is an S-VHS VCR with an S-Video output. I picked a JVC HR-S9500 which met these requirements and also had a built in Timebase corrector (TBC).

If you can’t find a VCR with a TBC, I’d recommend purchasing a Panasonic DVD Recorder from the mid 2000’s era as these have “Frame adjusters” which work in a similar manner to a TBC and can be quite effective at producing a clean output for your capture card.

For the capture card, I tried 3 devices:

  • EasyCAP
  • Dazzle DVC-100
  • Hauppauge USB-Live2

I tried the EasyCAP first as it was one that I had lying about and found the results to be incredibly poor and unusable with a low frame rate, lack of detail, and overly saturated colours. Frankly, it was only worth throwing in the bin!

I had a Dazzle DVC-100 USB Capture Device available to me by a relative. Unfortunately, while the picture quality was OK, the audio was out of sync when using on Linux. It was possible to use the device on Windows with VirtualDub but I did not want to do this.

Finally, I went on Amazon and bought a Hauppauge USB-Live2 for a reasonable price of £32 (At the time of writing). While you could pay more for a capture card, I do think the return on results would diminish after this point (especially considering we are dealing with VHS tapes which were never fantastic quality to begin with!)

FFMPEG Script - Capture

The first stage of this process is to capture the raw interlaced video from the capture card. For the video codec, I have written a bash script to handle all of my requirements for the process:


# VCR Capture Script for a Hauppage! USB-Live2

# === Declarations ===
RecordTime="02:00:00" # 2 Hours for SP

VIDEO_INPUT=1 #1 for S-Video

#=== Configure Capture Card ===
#Set to PAL-I
v4l2-ctl -d $videosource -s PAL-I
#Set the Input to S-Video for the USB-Live2 Card
v4l2-ctl -d $videosource --set-input=$VIDEO_INPUT --set-fmt-video=width=$VIDEO_WIDTH,height=$VIDEO_HEIGHT,pixelformat=$PIXEL_FORMAT --set-ctrl=mute=0

#=== Capture raw and lossless ===

#Determine the filename for the raw file
Filename=$(date +%Y%m%d_%H%M%S)

~/nvidia/ffmpeg/ffmpeg -ar 48000 -f alsa -thread_queue_size 1024 -i $audiosource -f v4l2 -ts abs -channel $VIDEO_INPUT -video_size $VIDEO_WIDTH'x'$VIDEO_HEIGHT -pix_fmt rgb565be -thread_queue_size 1024 -i $videosource -c:v huffyuv -level 3 -g 1 -aspect 4:3 -flags +ilme+ildct -aspect 4:3 -pix_fmt yuv422p -aspect 4:3 -c:a pcm_s16le $Filename.avi

Not only does this script handle the capturing of the video, but it also ensures that the capture card is configured to suit my requirements (e.g. Using S-Video instead of defaulting to Composite, PAL Format)

FFMPEG Script - Transcode

To transcode the video, I wrote a bash script which will loop through a directory of AVI files and deinterlace and upscale outputting to an MP4 File:


# VHS/Hi8 Deinterlace and Upscale Script
# William Wright M6WIQ

# === Declarations ===

# See https://ffmpeg.org/ffmpeg-filters.html for information,

# remove overscan:
CROP_FRAME="crop=(iw-10):(ih-14):3:0, pad=iw+10:ih+14:(ow-iw)/2:(oh-ih)/2"
# noise reduction
# upscale
VIDEO_CODEC="hevc_nvenc" #hevc_nvenc

mkdir output

for f in *.avi

   # Check to see if file exists
   if [ -f "$OUTPUT" ]; then
      echo "$OUTPUT exists."
      echo "$OUTPUT does not exist."
      echo "Converting $f..."

     ~/nvidia/ffmpeg/ffmpeg -hwaccel cuda -hwaccel_output_format cuda -threads 8 -i "$f" -standard PAL -aspect 4:3 -r $DEINTERLACED_FRAMERATE -c:v $VIDEO_CODEC -rc $RC_MODE -crf 23 -b:v 0 -filter:v "$TRANSCODE_VIDEO_FILTERS" -pix_fmt $PIXEL_FORMAT -movflags +faststart -c:a $AUDIO_CODEC -b:a 256k -hide_banner "$OUTPUT"


Essentially, the script functions break down into:

  • Deinterlace the video using the BWDIF filter
  • Perform noise reduction with the nlmeans filter
  • Upscale to 720p (4:3 aspect ratio)
  • Sharpen the video with the unsharp filter
  • Crop the frame so the head switching lines are not shown on the output

The results

To see the results of this, I have uploaded some the videos to Youtube…


A simple way to handle the capturing of over 50+ Hours of old VHS Tapes to preserve for the future.

Sources cited

I am extremely greatful for the various sources on the Web which assisted me in developing this process, such as:

LinuxTV.org V4L Capture Script

SuperUser - ffmpeg settings for VHS mpeg2/mp2 to H264/MP4 VBR conversion and reducing file size

The Doom 9 Forum

Videohelp Forum

My First Post

The aim of this site is to document and share tutorials and resources for various topics (Automation, Linux, Ham Radio and Computing etc.).

Hope you enjoy the site!