Converting VHS and DV to Modern Formats - Part 1

Over the past 10 years I've been meaning to convert my family's VHS tapes to a
modern format. Originally that would have been DVD, but as it seems that DVD
and Blu-Ray would have a limited lifespan, I've opted to go directly to modern
encoding formats.

---

This will be a multi-part series stepping through all the challenges with
converting these formats using Linux. This post, focuses around getting Video
Grabber's (USB Dongles) to work under Linux.

---

In order to get VHS content to a modern video format, you will need a compatible
USB capture device, a VHS Player and a PC. 

The process should be fairly straight forward, but there were a number of issues
which made the task difficult to achieve without compromise.

Conceptually it should be as follows:

1. Connect VHS Player to USB Capture Device
2. Connect USB Capture Device to PC
3. Install-\>Launch Capture software
4. Press Record in the Software
5. Press Play on the VHS player

Step 2 is where it get's tricky on Linux. While there are a significant number
of capture devices supported on Linux, it is still *luck-of-the-draw* when
purchasing a device with Linux in mind. 

From what I have found many devices are rebranded. E.g. Four same branded
devices may contain 4 different chipsets. Maybe only 2 of them contain the Linux
supported chipset. To make matters worse, vendors don't typically list the
chipset on their site or packaging.

The following is a description of my journey to get a couple of different
capture devices to work on Linux. Your mileage may vary.

In my case, I had two USB capture devices. One was very old *Pinnacle Dazzle*
obtained from my Dad that he was throwing out and the other was purchased at
[Aldi](https://www.aldi.com.au/) by my Mother-In-Law. This one had no label on
the device, but the box stated:  
*Bauhn DVD Maker*

### Dazzle

I started with the Dazzle. This unit looked very old. Sometimes with Linux, Old=
Good. As devices age, the likelihood that some enthusiastic Linux hacker will
add driver support goes up (I don't actually know this and cannot prove it, but
you probably can't disprove it either, so there).

So, I plugged it in and typed `lsusb`

        Bus 003 Device 007: ID 2304:021d Pinnacle Systems, Inc. Dazzle DVC130

*Figure 1. Content snipped for brevity*

The important part of the `lsusb` output is the ID `2304:021d`

We now know what this beast is. Let's check if the kernel has already recognized
it. You can usually do this by checking your kernel messages and see if a driver
module loaded and told you it registered anything. Therefore: `dmesg`

        [14842.638559] usb 3-11.3: new high-speed USB device number 7 using xhci_hcd
        [14842.714905] usb 3-11.3: New USB device found, idVendor=2304, idProduct=021d, bcdDevice= 0.00
        [14842.714907] usb 3-11.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
        [14842.714908] usb 3-11.3: Product: DVC 130
        [14842.714909] usb 3-11.3: Manufacturer: Pinnacle Systems, Inc.
        [14843.570702] usb 3-11.2: reset low-speed USB device number 5 using xhci_hcd

*Figure 2*

The output shows the `idVendor` and `idProduct` match the ID from the output of
`lsusb` in *Figure 1*

Essentially, the kernel is reporting the USB device, but the absence of messages
from drivers other than `usb` are not a good sign.

We know by the output of `dmesg` that a kernel module has not loaded. It is time
to check that the kernel modules we need are indeed compiled and available.
Luckily for me, I'm running [Gentoo](https://gentoo.org) so always have the
kernel source at hand. With video capture devices, these parts of the kernel are
referred to as the Video For Linux subsystem.
_(Technically, Video for Linux 2)_

These kernel modules can be found under: Drivers-\>Media-\>USB. 

            Device Drivers  --->
                <*> Multimedia support  --->
                    [*] Analog TV support
                    [*] Media USB Adapters  --->
                        <M> USB video devices based on Nogatech NT1003/1004/1005
                        <M> STK1160 USB video capture support
                        <M> WIS GO7007 MPEG encoder support
                        <M>   WIS GO7007 USB support
                        <M>   WIS GO7007 Loader support
                        <M> Conexant cx231xx USB video capture support
                        <M> Empia EM28xx USB devices support

*Figure 3 shows kernel options to enable video capture*

After enabling all the relevant looking ones, I compiled them all and unplugged
and re plugged my device, then checked `dmesg` again. Still no luck.

This is the point I recommend most people give up. I myself am not a big fan of
giving up. So what do I do? I bust out my trusty screw driver and pop that
sucker open to see whats _inside_. Under the magnifying glass I read out and 
google all the names on the chips. One of them catches my eye:

*go7007*

Well would you look at that. There is a module for this chipset. Perhaps all we
need to do, is _teach_ it to use my USB device. I start exploring the `.c` files
to find which one of them contains definitions looking like USB device and 
product IDs. I began poking around in the source files looking for a `struct`
recording all the supported USB Product and Device ID's.

Here is the `struct` I found in `go7007-usb.c`

            static const struct usb_device_id go7007_usb_id_table[] = {
                {
                            .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
                                                    USB_DEVICE_ID_MATCH_INT_INFO,
                            .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
                            .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
                            .bcdDevice_lo   = 0x200,   /* Revision number of XMen */
                            .bcdDevice_hi   = 0x200,
                            .bInterfaceClass        = 255,
                            .bInterfaceSubClass     = 0,
                            .bInterfaceProtocol     = 255,
                            .driver_info    = (kernel_ulong_t)GO7007_BOARDID_XMEN,
                    
                },
                {}
            };

*Figure 4*

The figure above is one device in the `struct,` so in `vim` of course, I yank 
yank a bit of text here and there and try to add support for my own USB device.
The main thing to get right, is to substitute the `idVendor` and `idProduct`
from the `struct` with the ID's we discovered in *Figure 1 and Figure 2*.

For other interfaces of the `struct` I'm mostly guessing, but hoping I can just
copy some of the other devices, recompile and it might work. But if it doesn't
work, change things around a bit, like some of the other cards and try again.  

If done correctly, the kernel module should load automatically when the device
is plugged in.

Sadly, I tried many combinations, caused a couple of kernel panics and sometimes
the card would load and I could get to see a blue screen when viewing the
device, but no content :( I was also able to setup a USB trace and see that the
driver was successfully uploading the firmware to the device.

In the end, I gave up on this device.

PS, I tried to capture using this device from a Windows VM. The device was so
old it would only work on 32-bit Windows 7 or older. While I was able to get
a driver, I could not find the original special software required to capture
and regular DirectShow capture to VirtualDub or OBS didn't work either.

### Bauhn DVD Maker

This devices seemed a tad more modern. It has cables for capturing Component 
and Composite. It came with a CD with drivers and software for Windows. Other
than that, there was little evidence online of this device. No-one mentioned
this model and certainly not in relation to Linux. I tried the obvious tests
(lsusb, dmesg) but didn't spend too much time trying to make it work for Linux.

On my Windows 7 VM though, I did have some luck. I got the software working
and was able to capture some VHS tapes. Although the capture was successful
there was no flexibility with the file format. The files came out in MPEG 2
(essentially DVD type files), which are okay, but if I wanted these files to
be online, I would need to re-encode them. That would mean a potential 
degradation in quality. I mean, come on! Haven't these videos degraded in
quality enough!

What I wanted to do, was for the videos to be captured in a near lossless format
and then re-encode to 2 files. 1 for showing on the internets (so that means
smallish file size, optimized for streaming and compatibility) and 2 for
archival purposes (use the most forward leaning tech available large close to
lossless).

My thinking is that future generations will be having to convert historical 
videos to another format and I want to make a large lossless file available
for that purpose.

I decided to crack open the Bauhn DVD maker and see what makes it tick.

![Close up picture of circuit board](images/connexent.jpeg)

Okay, I know how to do this, google all the little numbers and words. It didn't
take long to discover the chip and the existing Linux module for this baby.
Like the `go7007`, the `cx231xx` module supports many devices that use this
chip. Again, I had a crack at setting up the .c driver and adding in the Product
and Device ID's to make it work. And guess what?

*Boom* It worked. And that, my friends is joy. I tested using VLC --> Media -->
Open Capture Device..., then click the 'Video device name' dropdown box and
choose /dev/video0

You can download my [patch file](files/cx231xx.patch) against kernel 4.19.44

Now onto the task of actually doing something with the video files which I will
cover in my next post.

Tags: linux, ffmpeg, gentoo, kernel
