How to make a DVD mix without Transcoding

by Andrew Howlett

Preface

Suppose you want to make a DVD of your favourite scenes from a collection of different DVDs. Most tools require that you decode the video to yuv (or yuv12) then code it back to mpeg2. Those transcoding tools work well and have excellent documentation. The problem is that the process of decoding the original mpeg2 stream, then recoding the stream to mpeg2 again degrades the video signal. Also, this transcoding process may take a long time to process. But since I am making a mix DVD, the final code format will be the same as the original, and therefore it should be possible to demultiplex the mpeg2 and ac3 streams from the original DVDs and use these streams as input to dvdauthor without having to transcode. But how to do it? I couldn't find any documentation. So I figured it out and I offer this short article which explains what to do.

One of the great things about linux is that when you approach a new problem, there are often two or three ways to do it. But that can also be a problem, because some of the tools work better than others. In fact, my experience was that one tool – mplayer – worked a lot better than the others. So I will explain how to do it using mplayer, and follow up with some notes regarding other tools.

Here is a list of the debian packages I used in this procedure. I'm not going to explain how to install the packages – there are many apt-get tutorials on the web. If you use a different distribution then you should be able to figure out which packages to use – or ask at linuxquestions.org.

Step 1: Rip the streams

The video and audio streams must be ripped separately. In this example, my source dvd only has a single audio stream but many dvd's have multiple audio streams. If your source dvd has multiple audio streams then you must specify the desired audio stream using the -aid switch.

bash$ mplayer -dumpvideo -dumpfile rip_1.m2v -chapter 1-5 dvd://3
MPlayer 1.0pre7-3.3.5 (C) 2000-2005 MPlayer Team
CPU: Intel Celeron 2/Pentium III Coppermine,Geyserville (Family: 6, Stepping: 10)
Detected cache-line size is 32 bytes
MMX2 supported but disabled
CPUflags:  MMX: 1 MMX2: 0 3DNow: 0 3DNow2: 0 SSE: 1 SSE2: 0
Compiled for x86 CPU with extensions: MMX SSE



Failed to open /dev/rtc: Permission denied (it should be readable by the user.)
Opening joystick device /dev/input/js0
Can't open joystick device /dev/input/js0 : Permission denied
Can't init input joystick
Setting up LIRC support...
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support.
You will not be able to use your remote control.
Playing dvd://3.
libdvdread: Using libdvdcss version 1.2.9 for DVD access
Reading disc structure, please wait...
There are 5 titles on this DVD.
There are 25 chapters in this DVD title.
There are 1 angles in this DVD title.

libdvdread: Attempting to retrieve all CSS keys
libdvdread: This can take a _long_ time, please be patient

libdvdread: Get key for /VIDEO_TS/VIDEO_TS.VOB at 0x0000012d
libdvdread: Elapsed time 0
libdvdread: Get key for /VIDEO_TS/VTS_01_0.VOB at 0x00000160
libdvdread: Elapsed time 0
libdvdread: Get key for /VIDEO_TS/VTS_01_1.VOB at 0x000029ac
libdvdread: Elapsed time 0
libdvdread: Found 1 VTS's
libdvdread: Elapsed time 0
DVD successfully opened.
Cache fill:  0.00% (0 bytes)    MPEG-PS file format detected.
Core dumped ;)

Exiting... (End of file)
bash$ mplayer -dumpaudio -dumpfile rip_1.ac3 -chapter 1-5 dvd://3
MPlayer 1.0pre7-3.3.5 (C) 2000-2005 MPlayer Team
CPU: Intel Celeron 2/Pentium III Coppermine,Geyserville (Family: 6, Stepping: 10)
Detected cache-line size is 32 bytes
MMX2 supported but disabled
CPUflags:  MMX: 1 MMX2: 0 3DNow: 0 3DNow2: 0 SSE: 1 SSE2: 0
Compiled for x86 CPU with extensions: MMX SSE



Failed to open /dev/rtc: Permission denied (it should be readable by the user.)
Opening joystick device /dev/input/js0
Can't open joystick device /dev/input/js0 : Permission denied
Can't init input joystick
Setting up LIRC support...
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support.
You will not be able to use your remote control.
Playing dvd://3.
libdvdread: Using libdvdcss version 1.2.9 for DVD access
Reading disc structure, please wait...
There are 5 titles on this DVD.
There are 25 chapters in this DVD title.
There are 1 angles in this DVD title.

libdvdread: Attempting to retrieve all CSS keys
libdvdread: This can take a _long_ time, please be patient

libdvdread: Get key for /VIDEO_TS/VIDEO_TS.VOB at 0x0000012d
libdvdread: Elapsed time 0
libdvdread: Get key for /VIDEO_TS/VTS_01_0.VOB at 0x00000160
libdvdread: Elapsed time 0
libdvdread: Get key for /VIDEO_TS/VTS_01_1.VOB at 0x000029ac
libdvdread: Elapsed time 0
libdvdread: Found 1 VTS's
libdvdread: Elapsed time 0
DVD successfully opened.
Cache fill:  0.00% (0 bytes)    MPEG-PS file format detected.
Core dumped ;)

Exiting... (End of file)

Step 2: Multiplex the streams

Next, I combine the mpeg2 and ac3 streams into a single dvd formatted mpeg stream. DVD formatted mpeg is a bit different from “normal” mpeg (something about empty VOBUs, read the mplex man page for more info). So it is very important to remember the -f 8 switch to specify dvd mpeg output.

bash$ mplex -f 8 -o rip_1.mpg rip_1.m2v rip_1.ac3
   INFO: [mplex] mplex version 1.8.0 (2.2.4 $Date: 2005/08/28 17:50:54 $)
   INFO: [mplex] File rip_1.m2v looks like an MPEG Video stream.
   INFO: [mplex] File rip_1.ac3 looks like an AC3 Audio stream.
   INFO: [mplex] Video stream 0: profile 8 selected - ignoring non-standard options!
   INFO: [mplex] Found 1 audio streams and 1 video streams
   INFO: [mplex] Selecting dvdauthor DVD output profile
   INFO: [mplex] Multiplexing video program stream!
   INFO: [mplex] Scanning for header info: Video stream e0 (rip_1.m2v) 
   INFO: [mplex] VIDEO STREAM: e0
   INFO: [mplex] Frame width     : 720
   INFO: [mplex] Frame height    : 480
   INFO: [mplex] Aspect ratio    : 4:3 display
   INFO: [mplex] Picture rate    : 29.970 frames/sec
   INFO: [mplex] Bit rate        : 8000000 bits/sec
   INFO: [mplex] Vbv buffer size : 229376 bytes
   INFO: [mplex] CSPF            : 0
   INFO: [mplex] Scanning for header info: AC3 Audio stream 00 (rip_1.ac3)
   INFO: [mplex] AC3 frame size = 896
   INFO: [mplex] AC3 AUDIO STREAM:
   INFO: [mplex] Bit rate       :    28672 bytes/sec (224 kbit/sec)
   INFO: [mplex] Frequency      :     48000 Hz
   INFO: [mplex] SYSTEMS/PROGRAM stream:
   INFO: [mplex] rough-guess multiplexed stream data rate    : 8399296
   INFO: [mplex] target data-rate specified               : 10080000
   INFO: [mplex] Setting specified specified data rate: 10080000
   INFO: [mplex] Run-in Sectors = 89 Video delay = 13019 Audio delay = 13019
   INFO: [mplex] New sequence commences...
   INFO: [mplex] Video e0: buf=      0 frame=000000 sector=00000000
   INFO: [mplex] Audio bd: buf=      0 frame=000000 sector=00000000
   INFO: [mplex] STREAM bd completed @ frame 61729.
   INFO: [mplex] STREAM e0 completed @ frame 118402.
   INFO: [mplex] Multiplex completion at SCR=177756598.
   INFO: [mplex] Video e0: buf= 231670 frame=118402 sector=00791202
   INFO: [mplex] Audio bd: buf=  11648 frame=118398 sector=00027436
   INFO: [mplex] VIDEO_STATISTICS: e0
   INFO: [mplex] Video Stream length:  1597461294 bytes
   INFO: [mplex] Sequence headers:     4554
   INFO: [mplex] Sequence ends   :        0
   INFO: [mplex] No. Pictures    :   118403
   INFO: [mplex] No. Groups      :     4554
   INFO: [mplex] No. I Frames    :     4554 avg. size 54414 bytes
   INFO: [mplex] No. P Frames    :    40986 avg. size 18101 bytes
   INFO: [mplex] No. B Frames    :    72864 avg. size  8341 bytes
   INFO: [mplex] Average bit-rate :  6469200 bits/sec
   INFO: [mplex] Peak bit-rate    :  8687600  bits/sec
   INFO: [mplex] BUFFERING min 15 Buf max 134306
   INFO: [mplex] AUDIO_STATISTICS: bd
   INFO: [mplex] Audio stream length 55310080 bytes.
   INFO: [mplex] Frames         :    61730
   INFO: [mplex] BUFFERING min 35 Buf max 6979
   INFO: [mplex] MUX STATUS: no under-runs detected.

Step 3: Repeat Steps 1 and 2 for every scene

Repeat the previous procedure for each scene that you want from each of the original DVDs to generate a separate mpeg file for each scene.

Step 4: Create a DVD menu

Now I have a collection of several scenes. I need a menu. Building a dvd menu by hand is tedious work (see my DVD Authoring tutorial). But the tovid utility automates the whole process. You must have the tovid dependencies installed, and there are lots of them, but once installed tovid works great. Here is an example of how to create a menu using the tovid makemenu command:

andrew@alatar:~$ makemenu -ntsc -dvd "Pilates Beginner Workout" "Pilates Intermediate Workout" "Energy Boost 1" "Energy Boost 2" -out PILATES
--------------------------------
makemenu
A script to generate DVD/(S)VCD menus
Part of the tovid suite, version 0.23
http://tovid.sourceforge.net/
--------------------------------
=========================================================
Font: "helvetica" does not appear to be available in ImageMagick.
The font "Helvetica" will be used instead.
=========================================================
Adding 4 titles to the menu:
Pilates Beginner Workout
Pilates Intermediate Workout
Energy Boost 1
Energy Boost 2
Creating the background canvas with the following command:
convert -size 720x480 gradient:blue-black -gravity center -matte makemenu.bg_canvas.1796.png
cat /dev/zero | sox -t raw -c 2 -r 48000 -w -s - makemenu.bg_silence.1796.wav trim 0 4
=========================================================
Creating the foreground canvas with the following command:
convert -size 576x384 xc:none -antialias   -font "Helvetica" -pointsize 24 -fill "#FFF" -stroke black   -strokewidth 3 -draw "gravity northwest  text 0,0 'Pilates Beginner Workout' text 0,30 'Pilates Intermediate Workout' text 0,60 'Energy Boost 1' text 0,90 'Energy Boost 2'"   -stroke none -draw "gravity northwest  text 0,0 'Pilates Beginner Workout' text 0,30 'Pilates Intermediate Workout' text 0,60 'Energy Boost 1' text 0,90 'Energy Boost 2'"   "makemenu.fg_canvas.1796.png"
=========================================================
Creating the highlighted titles with the following command:
convert -size 576x384 xc:none +antialias   -font "Helvetica" -pointsize 24 -fill "#0F0"   -draw "gravity northwest  text 0,0 'Pilates Beginner Workout' text 0,30 'Pilates Intermediate Workout' text 0,60 'Energy Boost 1' text 0,90 'Energy Boost 2'"   -type Palette -colors 3   png8:makemenu.fg_highlight.1796.png
=========================================================
Creating the selection titles with the following command:
convert -size 576x384 xc:none +antialias   -font "Helvetica" -pointsize 24 -fill "#F00"   -draw "gravity northwest  text 0,0 'Pilates Beginner Workout' text 0,30 'Pilates Intermediate Workout' text 0,60 'Energy Boost 1' text 0,90 'Energy Boost 2'"   -type Palette -colors 3   png8:makemenu.fg_selection.1796.png
=========================================================
Compositing foreground canvas over background with the following command:
composite -compose Over -gravity center   makemenu.fg_canvas.1796.png makemenu.bg_canvas.1796.png -depth 8 "PILATES.ppm"
=========================================================
Compositing highlighted titles with the following command:
composite -compose Src -gravity center   makemenu.fg_highlight.1796.png makemenu.bg_canvas.1796.png png8:"PILATES.hi.png"
=========================================================
Compositing selection titles with the following command:
composite -compose Src -gravity center   makemenu.fg_selection.1796.png makemenu.bg_canvas.1796.png png8:"PILATES.sel.png"
=========================================================
Converting to video with the following command:
ppmtoy4m -S 420mpeg2 -A 10:11 -F 30000:1001 -n 119 -r "PILATES.ppm" 2>>/dev/null |   mpeg2enc -a 2 -f 8 -F 4 -n n -o "PILATES.m2v" >> /dev/null 2>&1
This may take a while...
=========================================================
Converting audio WAV to ac3 with the following command:
ffmpeg -i "makemenu.bg_silence.1796.wav" -ab 224 -ar 48000     -ac 2 -acodec ac3 -y "PILATES.ac3" >> /dev/null 2>&1
=========================================================
Multiplexing video and audio with the following command:
mplex -V -f 8 -o "PILATES.mpg"   "PILATES.m2v" "PILATES.ac3" >> /dev/null 2>&1
=========================================================
Multiplexing menu selection highlight and menu with the following command:
spumux "PILATES.xml" < "PILATES.mpg" > "PILATES.temp.mpg" 2>>/dev/null
=========================================================
Cleaning up...
=========================================================
Done. Your completed menu should be in the file PILATES.mpg.
You can use this menu on a DVD disc by invoking:

  makexml -dvd -menu PILATES.mpg <title 1> <title 2> ... <output name>

where <title X> is an MPEG video file corresponding to title X as listed
on your menu. Run 'makexml' without any options for more usage information.
=========================================================
Thanks for using makemenu!

This gives me a menu file named PILATES.mpg and a file named PILATES.xml. The xml file is the spumux config file which tovid forgot to delete. You don't need the xml file; you can delete it.

Step 5: Create a dvd filesystem

Next I need a dvdauthor xml file. Here is my dvdauthor xml file.

bash$ cat dvd.xml
<dvdauthor dest="my_dvd">
  <vmgm>
  </vmgm>
  <titleset>
    <menus>
      <pgc entry="root">
        <button name="button1"> jump title 1; </button>
        <button name="button2"> jump title 2; </button>
        <button name="button3"> jump title 3; </button>
        <button name="button4"> jump title 4; </button>
        <vob file="PILATES.mpg" pause="inf"/>
      </pgc>
    </menus>
    <titles>
      <pgc>
        <vob file="rip_1.mpg" chapters="0,6:26,7:38" pause="2"/>
        <post>
          jump menu;
        </post>
      </pgc>
      <pgc>
        <vob file="rip_2.mpg" chapters="0,2:12" pause="2"/>
        <post>
          jump menu;
        </post>
      </pgc>
      <pgc>
        <vob file="rip_3.mpg" pause="2"/>
        <post>
          jump menu;
        </post>
      </pgc>
      <pgc>
        <vob file="rip_4.mpg" pause="2"/>
        <post>
          jump menu;
        </post>
      </pgc>
    </titles>
  </titleset>
</dvdauthor>

And here is the command to create the dvd filesystem:

bash$ dvdauthor -x dvd.xml
DVDAuthor::dvdauthor, version 0.6.11.
Build options: gnugetopt magick iconv freetype fribidi
Send bugs to <dvdauthor-users@lists.sourceforge.net>

INFO: Locale=en_US
INFO: Converting filenames to ISO-8859-1
INFO: dvdauthor creating VTS
STAT: Picking VTS 01

STAT: Processing rip_1.mpg...
STAT: VOBU 4544 at 1605MB, 1 PGCS
INFO: Video pts = 0.144 .. 1975.501
INFO: Audio[0] pts = 0.144 .. 1975.504
STAT: VOBU 4554 at 1607MB, 1 PGCS
INFO: Generating VTS with the following video attributes:
INFO: MPEG version: mpeg2
INFO: TV standard: ntsc
INFO: Aspect ratio: 4:3
INFO: Resolution: 720x480
INFO: Audio ch 0 format: ac3/2ch, 48khz drc

... stuff deleted ...

STAT: fixed 4554 VOBUS                         
INFO: dvdauthor creating table of contents
INFO: Scanning my_dvd/VIDEO_TS/VTS_01_0.IFO

Step 6: Create an ISO Image and burn

Create the iso image and burn. You might have to burn as root.

bash$ mkisofs -dvd-video -o my_dvd.iso my_dvd/
bash$ growisofs -dvd-compat -Z /dev/dvd=my_dvd.iso

That's it. Now you should have a mix DVD.

Standard Disclaimer

Of course, in some jurisdictions (e.g. The Land of The Free, ha ha ha) it might be illegal to copy scenes from DVD's which you have legally purchased. It might be illegal to use the tools which I mention in this howto. And it might be illegal to even read this document! If you live in such a country then you should not do any of the actions described above.

Other stuff

Here are some notes regarding utilities that I tested but decided not to use.

dvdrip

I wanted to try dvdrip because a friend told me that dvdrip has a gui front end under X, which is very pretty. Dvdrip was pretty and easy to use. I ripped the title I wanted (title 3 of titleset 1) to hard drive, which produced two vob files. Switching to the command line, I used cat to concatenate the second vob file to the first. Then I used tcextract to extract each stream from the vob and mplex to multiplex the streams back together.

The dvdrip/tcextract/mplex procedure worked, but mplayer can do the job of dvdrip and tcextract in one command, so I used mplayer instead.

dvdbackup

dvdbackup is a powerful utility for backing up dvd's to hard drive. It should also be possible to rip selected chapters to hard drive. For instance,

andrew@alatar:~$ dvdbackup -i /dev/dvd -t 3 -s 4 -e 5 -o dvd 
libdvdread: Using libdvdcss version 1.2.9 for DVD access

libdvdread: Attempting to retrieve all CSS keys
libdvdread: This can take a _long_ time, please be patient

libdvdread: Get key for /VIDEO_TS/VIDEO_TS.VOB at 0x0000012d
libdvdread: Elapsed time 0
libdvdread: Get key for /VIDEO_TS/VTS_01_0.VOB at 0x00000160
libdvdread: Elapsed time 0
libdvdread: Get key for /VIDEO_TS/VTS_01_1.VOB at 0x000029ac
libdvdread: Elapsed time 0
libdvdread: Found 1 VTS's
libdvdread: Elapsed time 0

Rips title 1 chapters 4 and 5 to a vob file. The problem I had with dvdbackup is that sometimes it generated two vob files. I tried concatenating these two vobs to one vob, first using cat then using tccat, but both times I ended up with errors when I tried to mplex the streams back together. Nevertheless, the dvdbackup info command is very useful:

andrew@alatar:~$ dvdbackup -I -i /dev/dvd
libdvdread: Using libdvdcss version 1.2.9 for DVD access

libdvdread: Attempting to retrieve all CSS keys
libdvdread: This can take a _long_ time, please be patient

libdvdread: Get key for /VIDEO_TS/VIDEO_TS.VOB at 0x0000012d
libdvdread: Elapsed time 0
libdvdread: Get key for /VIDEO_TS/VTS_01_0.VOB at 0x00000160
libdvdread: Elapsed time 0
libdvdread: Get key for /VIDEO_TS/VTS_01_1.VOB at 0x000029ac
libdvdread: Elapsed time 0
libdvdread: Found 1 VTS's
libdvdread: Elapsed time 0



DVD-Video information of the DVD with title PILATES_IMWO

File Structure DVD
VIDEO_TS/
        VIDEO_TS.IFO    12288
        VIDEO_TS.VOB    12288
        VIDEO_TS.BUP    12288
        VTS_01_0.IFO    47104
        VTS_01_0.VOB    21127168
        VTS_01_1.VOB    1073709056
        VTS_01_2.VOB    1073709056
        VTS_01_3.VOB    662702080
        VTS_01_0.BUP    47104


Main feature:
        Title set containing the main feature is  1
        The aspect ratio of the main feature is 4:3
        The main feature has 1 angle(s)
        The main feature has 1 audio_track(s)
        The main feature has 0 subpicture channel(s)
        The main feature has a maximum of 25 chapter(s) in on of its titles
        The main feature has a maximum of 2 audio channel(s) in on of its titles


Title Sets:

        Title set 1
                The aspect ratio of title set 1 is 4:3
                Title set 1 has 1 angle(s)
                Title set 1 has 1 audio_track(s)
                Title set 1 has 0 subpicture channel(s)

                Titles included in title set 1 is/are
                        Title 1:
                                Title 1 has 1 chapter(s)
                                Title 1 has 2 audio channel(s)
                        Title 2:
                                Title 2 has 1 chapter(s)
                                Title 2 has 2 audio channel(s)
                        Title 3:
                                Title 3 has 25 chapter(s)
                                Title 3 has 2 audio channel(s)
                        Title 4:
                                Title 4 has 1 chapter(s)
                                Title 4 has 2 audio channel(s)
                        Title 5:
                                Title 5 has 1 chapter(s)
                                Title 5 has 2 audio channel(s)

Transcode

The whole point of this experiement was not to transcode the video stream. So why use transcode? Because transcode includes some handy utilities such as tcextract, which can extract individual streams from vob files. For instance:

bash$ tcextract -i rip_1.vob -x mpeg2 -t vob > rip_1.m2v
tc_memcpy: using mmxext for memcpy
bash$ tcextract -i rip_1.vob -x ac3 -t vob > rip_1.ac3
tc_memcpy: using mmxext for memcpy

Now the m2v and ac3 files may be multiplexed to create a dvd compliant mpeg file. Transcode worked ok with dvdrip, but not with dvdbackup. Furthermore, mplayer does the rip and extract in one step, so I used mplayer not transcode.