Bulk DVD Creation With Tovid

Today I’m going to show you how I automated the DVD creation part of the VHS home video conversion process. I’m assuming you have already captured the video to your computer somehow, and just want to make DVDs with your captured video.

Note: All of these tools are Linux command line tools. Less convenient than a GUI, but much more appropriate for bulk operations and scripting.

Preparing the Videos

Tovid can take any video format and make a DVD from it by calling ffmpeg and other libraries when it needs to. In practice, I find that tovid and ffmpeg fight like sibling when they get along it’s true love, but when they fight things get broken.

Encoding is the slowest part of making a DVD, so we’ll do it separately. This way we can tweak the DVD quickly without re-encoding each time. FFMpeg can do it with the command:

ffmpeg -i SourceFile.whatever -target ntsc-dvd outputfile.mpg

This will produce mpeg2 files which don’t need to be further encoded in order to be put on a DVD.

Splitting Videos

If the resulting outputfile.mpg is too big for a DVD, you will need to split it. FFMpeg can split your file using a starting second (-ss) and a time (-t).  With this syntax you can break your file into as many pieces as you need to fit them on a DVD.

ffmpeg -i SourceFile.whatever -ss 0 -t 7200 -target ntsc-dvd outputfile-part1.mpg
ffmpeg -i SourceFile.whatever -ss 7201 -target ntsc-dvd outputfile-part2.mpg

Creating the Metadata

Tovid will want a couple of pieces of metadata, depending on what menu options you choose. Main titles, submenu titles and a disc title.

Since I was digitizing family videos, I wanted the disc title to be the years spanned. So I created a CSV file with 4 columns. the year would become the disc title.

filename,year,long description,short description
SourceFile.whatever,1990,The family goes sledding at Ice Hill,Sledding

The Tovid Wrapper Script

I know Tovid is already a wrapper for dvdauthor, ffmpeg and whatever other tools it uses behind the scenes, but what’s another layer, right?

I put all of my videos, the CSV file and this script in a folder:

#!/usr/bin/env php
<?php

/*
 * @brief Make as few DVDs as needed to fit all of the videos listed in a CSV file
 *
 * Copyright Michael Moore <stuporglue@gmail.com>
 * This script assumes that
 *      * All of the videos have already been encoded into mpeg2 format for DVD
 *      * All of the videos paths are relatie to INPUTDIR
 *
 * As many videos are fit into one DVD as possible. Videos are added in the order
 * listed in the CSV file. If a video is too big for a DVD the script will tell
 * you, and then exit. DVDs are named either "year", "year1 - year2" or
 * "year disc n", using the year from the CSV.
 *
 * Requires php-cli installed so that we can fork processes.
 *
 * Our metadata.csv file format:
 * pathtofile,year,looooooooooooong title here,short title
 *
 * We assume the file has a header row.
 */

//
//         Settings
//
define('DVDSIZE',8500000000); // Our estimate of the number of bytes available on a DVD+R DL
define('MENUOVERHEAD',45*1024*1024); // Generous leeway for the menu system
define('INPUTDIR',"/home/myuser/videos/input/"); // starting point for all file paths. Use / for abs. paths
define('TMPDIR','/tmp/tovid/'); // Where do you want the tmp files?
define('OUTDIR',"/home/myuser/videos/DVDs/"); // Destination?
define('MAXCHILDREN',5); // How many tovids to run simultaneously? Probably 1-2 less than the # of cores available?
$fh = fopen(INPUTDIR.'/metadata.csv','r');

//
//         No Lifeguard on duty!
//
@mkdir(TMPDIR);
chdir(TMPDIR); // Tovid likes to dump in the cwd. Chdir so that tovid dumps its temp files somewhere usefulish

define('MAXVOB',1073709056); // The max size of a single VOB
global $pids;
$pids = Array();

$currentdvdsize = MENUOVERHEAD;
$currentdvdfiles = Array();
fgetcsv($fh); // remove header from csv file
while($file = fgetcsv($fh)){

    // Fast check!
    if((filesize(INPUTDIR .'/'. $file[0]) + $currentdvdsize) > DVDSIZE){
    makeDVD($currentdvdfiles); // Make a DVD!

    $currentdvdfiles = Array(); // Reset!
    $currentdvdsize = MENUOVERHEAD;
    }

    $currentdvdfiles[] = $file;

    // Calculate how much space this video will take on the disc
    // dvdauthor seems to:
    // 1) Never mix videos in the same VOB
    // 2) Make all VOBs except the last one come out to MAXVOB size (the last one can be whatever size smaller than MAXVOB)
    $currentdvdsize += (MAXVOB * ceil(filesize(INPUTDIR .'/'. $file[0])/MAXVOB));

    if($currentdvdsize > DVDSIZE){
    die("It looks like {$file[0]} is too big to fit on a DVD!\n");
    }
}

// Make any remnants
if(count($currentdvdfiles) > 0){
    makeDVD($currentdvdfiles);
}

function makeDVD($files){
    global $pids;

    // Make title
    $last = count($files) - 1;
    if($files[0][1] != $files[$last][1]){
    $title = "{$files[0][1]} - {$files[$last][1]}";
    }else{
    $title = "{$files[0][1]}";
    }

    $count = 2;
    $origtitle = $title;
    while(file_exists(OUTDIR . "/$title")){
    $title = "$origtitle disc $count";
    $count++;
    }

    // List of files
    $input = Array();
    $shorttitles = Array();
    $fulltitles = Array();
    foreach($files as $file){
    $input[] = INPUTDIR . "/{$file[0]}";
    $fulltitles[] = $file[2];
    $shorttitles[] = $file[3];
    }

    $cmd = "tovid disc
    -files  " . implode(" ",array_map('escapeshellarg',$input)) . "
    -titles " . implode(' ',array_map('escapeshellarg',$shorttitles)) . "
    -menu-title " . escapeshellarg($title) . "
    -menu-fontsize 18
    -title-color '#ff7700'
    -title-stroke black
    -titles-fontsize 18
    -titles-color '#ff7700'
    -showcase-titles-align east
    -rotate 5
    -wave default
    -submenus
    -submenu-titles " . implode(' ',array_map('escapeshellarg',$fulltitles)) . "
    -submenu-title-color '#ff7700'
    -submenu-stroke black
    -loop 0
    -submenu-length 20
    -noask
    -out " . escapeshellarg(OUTDIR . "/$title");

    // Now wait for our turn...
    while(count($pids) >= MAXCHILDREN){
    $status = NULL;
    $exited_pid = pcntl_wait($status);            
    if(pcntl_wexitstatus($status) != 0){
        print "FAILURE IN " . TMPDIR . "/tovid.$exited_pid!!!\n{$pids[$exited_pid]}\n";
    }
    unset($pids[$exited_pid]);
    }

    $cmd = str_replace("\n",' ',$cmd);

    print "LAUNCHING!!!\n$cmd\n";

    $pid = pcntl_fork();
    if($pid == -1){
    die("COULDNT FORK!");
    }else if($pid){
    $pids[$pid] = $cmd;
    sleep(3); // give tovid a chance to claim its temp directories
    }else{
    $cmd .= " > " . TMPDIR . "/tovid." . getmypid() . " 2>&1";
    exec($cmd);
    exit();
    }
}

Using the Script

Save the PHP script above to a file named tovidBatch.php and make it executable.

Edit the defined constants to fit your directories and output media (DVDSIZE). If desired, edit the tovid disc command to build your DVDs the way you want them.

Finally, run (on a command line)

php tovidBatch.php

Your videos are on their way!

Sample DVD Menu
Sample DVD Menu

This entry was posted in Computers, Something Interesting and tagged , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *