Tuesday, February 12, 2019

datvideo: Storing Video on Digital Audio Tape (DAT)

About a year ago I added a Digital Audio Tape (DAT) deck to my home theater system. I was turned onto the format by popular Youtuber Techmoan and a great video that he produced: Digital Audio Tape: The one DAT got away. I had wanted to add magnetic tape to my home theater for some time and this highly unique format seemed like a perfect choice.

Big Buck Bunny from DAT Tape
Shortly after purchasing the deck I realized that I could likely store any arbitrary binary data on the tape with the S/PDIF input/output. It would be really cool to merge some modern high-compression video codec with this antiquated format. Over this weekend I decided to do just that.

I wrote a small tool called datvideo that allows storing arbitrary binary data on the tape. This tool is used to grab raw audio binary data from a sound card, search for frames of binary data, decode them and emit them into another file. This can be assembled into a pipeline to feed video data into a player such as mplayer. How cool is that?

Sony DTC-690, below Marantz Blu-Ray, AV Receiver and New-Old-Stock DAT Tapes
In this article, I will walk you through how I pulled this off.

What is DAT?

The DAT format is especially interesting to me because it is highly advanced for the time of its debut in the late 1980's. The DAT format specifies uncompressed 48kHz, 2-channel, 16-bit PCM audio data. The fact that it is uncompressed blew my mind. This is a format that exceeds Red Book CD audio specifications coupled with the charm of an unusual format. I picked up a Sony DTC-690 from Craigslist that was in great working order. There is just something really sweet about mid-90s Sony gear and their perfectly labelled switches. It fits in well on the shelf with my more modern Marantz components.

DAT Tapes - Smaller than a cassette
The DAT format never caught on in the consumer market for a variety of reasons but did gain some success in the professional recording industry. The tapes were popular to use as masters. This makes sense given the fact that the data is uncompressed and stored at a high sample rate. The tapes come in a variety of lengths. I have 35, 65 and 60 minute tapes.

Arbitrary Binary Data on a DAT Tape

The DAT tape decks include a digital input and output. These take the sample data provided to them and commit it directly to tape. This is great for audio because you can make a perfect copy of any input source. I had the idea that any arbitrary data could be fed into the digital input. It doesn't necessarily need  to be real audio sample data.

Before spending any time on this project, I worked out the data rate of the tape to make sure I could do something meaningful with it. The calculation is quite simple:

$$ Bandwidth = SampleRate * BytesPerSample * ChannelCount\\ Bandwidth = 48000 * 2 * 2\\ Bandwidth = 187.5kB/s $$This is decently high bandwidth and likely high enough to support modern video codecs. Once I had demonstrated that there was enough bandwidth available on the tape I started to write the datvideo tool.


In order to store arbitrary binary data on the tape, I would need a way to synchronize the receiver with the data on the tape. There could be some audio data, followed by a binary blob, followed by more audio data. The receiver does not know when it will receive a specific type of data, so a system must be devised to signal to the receiver that some binary data has begun. It would also be nice to have some error handling in the form of a CRC. Though it is unlikely that the hardware will introduce errors in the data, it is possible that something in the audio path could introduce some unexpected behavior (some gain on the signal, or the like).

RFC1662 Frame Format
I opted to use the frame format specified by RFC-1662 which is commonly used in PPP (point-to-point) networking. The nice thing about this format is that it is easy to implement, has some error handling and can easily mix in with other forms of data thanks to the escaping feature. More details can be found in the specification.

Audio Hardware

I used a cheap USB sound card to send/receive data to/from the DAT deck. The sound card that I selected has S/PDIF inputs and outputs. I will use a TOSLINK cable to connect this sound card to the DAT deck.

USB Sound Card Ports
When the binary data stored on the tape is played back, it sounds like noise and pins the level meter. It is interesting when music is interrupted with binary data and the music resumes.

Level Meters during Data Playback
In order to test all of this, I created a loopback on the sound card so that I could avoid using the tape deck during development.

S/PDIF Loopback for Testing without the DAT deck

Encoding/Decoding Tapes: datvideo

I wrote a tool called datvideo that helps with this project. It has two modes: encode and decode. The encode mode takes an input file and generates a raw "audio" file that is intended to be recorded to the tape. The decode mode takes captured raw "audio" data and extracts data from the RFC-1662 frames. The tool can be configured to read/write from files or stdin/stdout. This makes it convenient for setting up a pipeline to read/write the tapes with. Here is the help output with a description of all command line flags that can be passed to the tool.
[andrew@andrew-laptop build]$ ./src/datvideo --help


   ./src/datvideo  {-e|-d} [-n <byte count="">] [-s <byte count="">]
                   [-o <path>] [-i <path>] [--] [--version] [-h]


   -e,  --encode
     (OR required)  Put the tool in encode mode.
         -- OR --
   -d,  --decode
     (OR required)  Put the tool in decode mode.

   -n <byte count="">,  --buffer_size <byte count="">
     The amount of data to buffer before writing to the out file. This is
     useful for streaming operations to ensure that there  is always data
     available to read for the client without blocking.

   -s <byte count="">,  --chunk_size <byte count="">
     The size of chunks to split the file into. This is useful for
     streaming operations, like audio/video.

   -o <path>,  --output_file <path>
     The output file to use for the current operation. Do not specify for

   -i <path>,  --input_file <path>
     The input file to use for the current operation. Do not specify for

   --,  --ignore_rest
     Ignores the rest of the labeled arguments following this flag.

     Displays version information and exits.

   -h,  --help
     Displays usage information and exits.

   A tool for storing binary data on DAT tapes.
The following commands generate a tape image and decode a captured tape image, respectively. This encodes a photo from a local car meet that I atteded recently. These commands can be chained together with aplay and arecord. More details on that next.
[andrew@andrew-laptop build]$ ./src/datvideo --encode \
-i car_meet_1.jpeg -o car_meet_1.bin
[andrew@andrew-laptop build]$ ./src/datvideo --decode \
-i car_meet_1.raw -o car_meet_1.jpeg

Raw Audio Hardware Access

Linux comes with a rich set of tools for working with audio. This demo requires the lowest level of access to the hardware, playing back and recording raw files. The aplay and arecord commands from the ALSA project allow exactly this. First, I will list out the sinks and sources. This can be done for both aplay and arecord.
# List out available audio sinks and sources
[andrew@andrew-laptop ~]$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: HDMI [HDA Intel HDMI], device 3: HDMI 0 [HDMI 0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 7: HDMI 1 [HDMI 1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 8: HDMI 2 [HDMI 2]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 9: HDMI 3 [HDMI 3]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 10: HDMI 4 [HDMI 4]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 0: ALC3232 Analog [ALC3232 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 2: Device [USB Sound Device], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
This allows me to determine that the hardware address of my USB sound card is "hw:2,0". It is also worth noting that I changed the default input and outputs in the pavucontrol app to S/PDIF in and out.

Minting a Tape

With all of this knowledge in hand, let's chain it together to allow video streaming from the tape deck and USB sound card. I decided to use Big Buck Bunny as a test, which is common when dealing with media and decoders/encoders.

Big Buck Bunny - Short Film from the Blender Project
So first, let's grab Big Buck Bunny from Renderfarming. I like the1080p, 60fps version for the buttery smooth visuals :]. The video is roughly 10 minutes long which means the file needs to be around 110MB to achieve real-time playback from the tape. The file is overweight at 356MB which means that some transcoding is needed to trim it down. I noticed that there is an extra audio track. That can be stripped out too.
# Strip the AC3 audio track. MP3 is smaller.
[andrew@andrew-laptop Downloads]$ ffmpeg \
-i bbb_sunflower_1080p_60fps_normal.mp4 -map 0:0 -map 0:1 \
-acodec copy -vcodec copy bbb_sunflower_1080p_60fps_normal_one_audio.mp4

# Transcode to h265 with CRF 30. This yeilds a ~100MB file.
andrew-desktop:Downloads andrew$ ffmpeg \
-i bbb_sunflower_1080p_60fps_normal_one_audio.mp4 -acodec copy \
-vcodec libx265 -crf 30 bbb_sunflower_1080p_60fps_normal_one_audio_h265.mp4
I used my Mac Pro for the heavy h265 transcoding so that my tiny ThinkPad T440s didn't have to work too hard and to speed up the operation.

Once the file was transcoded into a file of suitable size, it was placed into MPEG-TS frames. MPEG-TS is typically used for DVB systems where interruptions in the stream may happen due to interference. Once the MPEG-TS stream was ready, the file was encoded with datvideo.
# Change the transport to MPEG-TS
[andrew@andrew-laptop Downloads]$ ffmpeg \
-i bbb_sunflower_1080p_60fps_normal_one_audio_h265.mp4 \
-f mpegts -vcodec copy -acodec copy \

# Encode the MPEG-TS to a tape image. Use 188 byte frames, which
# happens to be the same as the MPEG-TS frame size ;)
[andrew@andrew-laptop build]$ ./src/datvideo --encode \
-i ~/Downloads/bbb_sunflower_1080p_60fps_normal_one_audio_h265.ts \
--chunk_size 188 -o big_buck_bunny.bin
Now that the image is ready, it is time to burn it to tape. First, the DAT deck is put into record mode. The DAT deck can be recording before starting to burn the image thanks to the RFC-1662 framing that allows detecting the start of binary data anywhere on the tape. The following aplay command is used to play the raw file to tape without modification.
# Play the track out to the DAT deck
[andrew@andrew-laptop build]$ aplay --format=S16_LE --device=hw:2,0 \
--channels=2 --rate=48000 --file-type=raw big_buck_bunny.bin
Now that the MPEG transport stream has been recorded to tape, it can be played back, decoded with datvideo and played back with VLC.
# Record from the DAT deck, piping into datvideo
# and decoding to a file 'bbb.ts'
[andrew@andrew-laptop build]$ arecord --format=S16_LE \
--device=hw:2,0 --channels=2 --rate=48000 \
--file-type=raw | ./src/datvideo --decode -o bbb.ts

# Open the file for playback with VLC
[andrew@andrew-laptop build]$ vlc bbb.ts
Let the file bbb.ts buffer for a few seconds and then it can be opened with VLC for playback. It is a pretty crude setup, but it works surprisingly well.

Weekend Projects :]

Closing Remarks

This was fun. I like doing quirky things with technology. I learned a few new things that I can probably use in my day-to-day work which is always nice. I probably won't go out and convert all of my favorite movies to DAT format, but this was certainly a nice way to spend a rainy weekend.

I hope you enjoyed my zany use of technology and perhaps are inspired to do something yourself. I know one idea that comes to mind is TCP/IP over TOSLINK optical audio cables via the datvideo tool shown above. It should work rather well.

Comments always welcome. Thanks for reading!

No comments :

Post a Comment

Note: Only a member of this blog may post a comment.