4/13/2005

Below is a python script I wrote to make a copy of a video DVD and burn it onto a writable DVD. This is a more complicated process than copying an audio CD because manufactured DVDs can hold around 8.5 gigabytes (GB) of data while your blank writable DVD can usually only hold 4.7 GB. So, this script goes through the process of taking the movie tract, decrypting it, separating out the video and audio, compressing the video as needed, combining the result back together, and burning it onto the blank DVD. I can’t tell any difference between the original and the copy, besides all the “extras” missing, so it works out well.

This script runs under Linux and requires python, vobcopy, libdvdcss, mjpegtools, transcode, dvdauthor, and dvd+rw-tools. Only use this script to copy DVDs you legally own for your personal use or else the MPAA will saw off your hands with a rusty butter knife. You have been warned!


#!/usr/bin/python

####
# Author: Chris Ladd
# File: copydvd.py
# Date: April 13, 2005
# License: GPL v2
####

import os;

# Change this to point to your DVD burner
DVD_BURNER = "/dev/hdb"

# Make sure we have a clean environment
os.chdir("/tmp")
os.system("rm -f *.vob")
os.system("rm -f *.vob.partial")
os.system("rm -f movie.m2v")
os.system("rm -f movie.ac3")
os.system("rm -f shrink.m2v")
os.system("rm -f movie*.mpg")
os.system("rm -f toc.xml")
os.system("rm -rf movie/")

# Copy the dvd movie track
assert os.system("vobcopy -l") == 0
assert os.system("mv *.vob movie.vob") == 0

# Separate the audio and video
assert os.system("tcextract -i movie.vob -t vob -x mpeg2 > movie.m2v") == 0
assert os.system("tcextract -i movie.vob -t vob -x ac3 -a 0 > movie.ac3") == 0

# Calculate how much we have to shrink the video
m2v_size = float(os.stat("movie.m2v")[6])
ac3_size = float(os.stat("movie.ac3")[6])
print "m2v size: %f" % m2v_size
print "ac3 size: %f" % ac3_size

factor = float(m2v_size / (4700000000.0 - ac3_size) * 1.02)
factor = round(factor, 2)
print "shrink factor: %f" % factor

# Shrink the video if necessary and put it back together with the audio
if factor > 1.0 :
    assert os.system("tcrequant -i movie.m2v -o shrink.m2v -f %f" % factor) == 0
    assert os.system("mplex -f 8 -o movie%d.mpg shrink.m2v movie.ac3") == 0
else :
    assert os.system("mplex -f 8 -o movie%d.mpg movie.m2v movie.ac3") == 0

# Write the DVD TOC so that the video starts playing once inserted
toc = open("toc.xml", "w")
toc.write('<dvdauthor>n  <vmgm />n  <titleset>n   <titles>n    <pgc>n')
for filename in os.popen("ls movie*.mpg") :
    toc.write('      <vob file="%s" />n' % filename[:-1])
toc.write('    </pgc>n   </titles>n  </titleset>n </dvdauthor>')
toc.close()

# Create the DVD image
assert os.system("dvdauthor -o movie -x toc.xml") == 0

# Burn the new DVD
assert os.system("growisofs -Z %s -dvd-video movie/" % DVD_BURNER) == 0

# Clean up
os.system("rm -f *.vob")
os.system("rm -f movie.m2v")
os.system("rm -f movie.ac3")
os.system("rm -f shrink.m2v")
os.system("rm -f movie*.mpg")
os.system("rm -f toc.xml")
os.system("rm -rf movie/")