75 changes: 31 additions & 44 deletions trunk/export/transcode/XviD.pm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/perl -w
#Last Updated: 2005.02.17 (xris)
#Last Updated: 2005.02.23 (xris)
#
# export::transcode::XviD
# Maintained by Chris Petersen <mythtv@forevermore.net>
Expand Down Expand Up @@ -32,17 +32,24 @@ package export::transcode::XviD;
'noise_reduction' => 1,
'deinterlace' => 1,
'crop' => 1,
# VBR-specific settings
'vbr' => 1, # This enables vbr, and the multipass/quantisation options
'multipass' => 0, # You get multipass or quantisation, multipass will override
'quantisation' => 6, # 4 through 6 is probably right...
# Other video options
'a_bitrate' => 128,
'v_bitrate' => 960, # Remember, quantisation overrides video bitrate
'width' => 624,
};
bless($self, $class);

# Verify any commandline or config file options
die "Audio bitrate must be > 0\n" unless (defined $self->val('a_bitrate') && $self->{'a_bitrate'} > 0);
die "Video bitrate must be > 0\n" unless (defined $self->val('v_bitrate') && $self->{'v_bitrate'} > 0);
die "Width must be > 0\n" unless (!defined $self->val('width') || $self->{'width'} =~ /^\s*\D/ || $self->{'width'} > 0);
die "Height must be > 0\n" unless (!defined $self->val('height') || $self->{'height'} =~ /^\s*\D/ || $self->{'height'} > 0);

# VBR, multipass, etc.
if ($self->val('multipass')) {
$self->{'vbr'} = 1;
}
elsif ($self->val('quantisation')) {
die "Quantisation must be a number between 1 and 31 (lower means better quality).\n" if ($self->{'quantisation'} < 1 || $self->{'quantisation'} > 31);
$self->{'vbr'} = 1;
}

# Initialize and check for transcode
$self->init_transcode();

Expand All @@ -57,36 +64,21 @@ package export::transcode::XviD;
# Load the parent module's settings
$self->SUPER::gather_settings();
# Audio Bitrate
if (arg('a_bitrate')) {
$self->{'a_bitrate'} = arg('a_bitrate');
die "Audio bitrate must be > 0\n" unless (arg('a_bitrate') > 0);
}
else {
$self->{'a_bitrate'} = query_text('Audio bitrate?',
'int',
$self->{'a_bitrate'});
}
$self->{'a_bitrate'} = query_text('Audio bitrate?',
'int',
$self->val('a_bitrate'));
# VBR options
if (arg('multipass')) {
$self->{'multipass'} = 1;
$self->{'vbr'} = 1;
}
elsif (arg('quantisation')) {
die "Quantisation must be a number between 1 and 31 (lower means better quality).\n" if (arg('quantisation') < 1 || arg('quantisation') > 31);
$self->{'quantisation'} = arg('quantisation');
$self->{'vbr'} = 1;
}
elsif (!$is_cli) {
if (!$is_cli) {
$self->{'vbr'} = query_text('Variable bitrate video?',
'yesno',
$self->{'vbr'} ? 'Yes' : 'No');
$self->val('vbr'));
if ($self->{'vbr'}) {
$self->{'multipass'} = query_text('Multi-pass (slower, but better quality)?',
'yesno',
$self->{'multipass'} ? 'Yes' : 'No');
$self->val('multipass'));
if (!$self->{'multipass'}) {
while (1) {
my $quantisation = query_text('VBR quality/quantisation (1-31)?', 'float', $self->{'quantisation'});
my $quantisation = query_text('VBR quality/quantisation (1-31)?', 'float', $self->val('quantisation'));
if ($quantisation < 1) {
print "Too low; please choose a number between 1 and 31.\n";
}
Expand All @@ -100,17 +92,12 @@ package export::transcode::XviD;
}
}
}
}
# Ask the user what audio and video bitrates he/she wants
if (arg('v_bitrate')) {
die "Video bitrate must be > 0\n" unless (arg('v_bitrate') > 0);
$self->{'v_bitrate'} = arg('v_bitrate');
}
elsif ($self->{'multipass'} || !$self->{'vbr'}) {
# make sure we have v_bitrate on the commandline
$self->{'v_bitrate'} = query_text('Video bitrate?',
'int',
$self->{'v_bitrate'});
# Ask the user what audio and video bitrates he/she wants
if ($self->{'multipass'} || !$self->{'vbr'}) {
$self->{'v_bitrate'} = query_text('Video bitrate?',
'int',
$self->val('v_bitrate'));
}
}
# Query the resolution
$self->query_resolution();
Expand Down Expand Up @@ -149,7 +136,6 @@ package export::transcode::XviD;
$self->{'transcode_xtra'} = " -y xvid $params"
." -R 2,/tmp/xvid.$$.log"
." -w $self->{'v_bitrate'} ";
$self->SUPER::export($episode, '.avi');
}
# Single pass
else {
Expand All @@ -160,8 +146,9 @@ package export::transcode::XviD;
else {
$self->{'transcode_xtra'} .= " -w $self->{'v_bitrate'} ";
}
$self->SUPER::export($episode, '.avi');
}
# Execute the (final pass) encode
$self->SUPER::export($episode, '.avi');
}

1; #return true
Expand Down
87 changes: 83 additions & 4 deletions trunk/nuv_export/cli.pm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/perl -w
#Last Updated: 2005.02.16 (xris)
#Last Updated: 2005.02.25 (xris)
#
# cli.pm
#
Expand All @@ -18,19 +18,80 @@ package nuv_export::cli;
use Exporter;
our @ISA = qw/ Exporter /;

our @EXPORT = qw/ &add_arg &arg &load_cli_args
our @EXPORT = qw/ &add_arg &load_cli_args
&arg &rc_arg
$export_prog $is_cli
$DEBUG
/;
}

# Load some options early, before anything else:
# --ffmpeg, --transcode. Default is --ffmpeg
our $export_prog = find_program('ffmpeg') ? 'ffmpeg' : 'transcode';
# --ffmpeg, --transcode and --config
our $export_prog = undef;
our $config_file = undef;
GetOptions('ffmpeg' => sub { $export_prog = 'ffmpeg'; },
'transcode' => sub { $export_prog = 'transcode'; },
'config|c=s' => \$config_file,
);

# Make sure the specified config file exists
if ($config_file && !-e $config_file) {
die "configuration file $config_file does not exist!\n\n";
}

# Load the nuvexportrc file
my %rc_args;
foreach my $file ($config_file, 'nuvexportrc', "$ENV{'HOME'}/.nuvexportrc", "/etc/.nuvexportrc") {
# No file
next unless ($file && -e $file);
# Slurp
local $/ = undef;
# Read the file
my $data = '';
open(DATA, $file) or die "Couldn't read $file: $!\n\n";
$data .= $_ while (<DATA>);
close DATA;
# Clean out any comments
$data =~ s/\s*#[^\n]*?\s*\n/\n/sg;
$data =~ s/\n\s*\n/\n/sg;
# Nothing there
next unless ($data);
# Parse the contents
while ($data =~ /<\s*([^>]+)\s*>(.+?)<\s*\/\s*\1\s*>/sg) {
my $section = lc($1);
my $args = $2;
while ($args =~ /^\s*(\S+?)\s*=\s*(.+?)\s*$/mg) {
my $var = lc($1);
my $val = $2;
# Boolean arg?
if ($val =~ /^([yt1]|yes|true)$/i) {
$rc_args{$section}{$var} = 1;
}
elsif ($val =~ /^([nf0]|no|false)$/i) {
$rc_args{$section}{$var} = 0;
}
else {
$rc_args{$section}{$var} = $val;
}
}
}
# Time to leave
last;
}

# Make sure the export_prog exists
if (!$export_prog) {
if ($export_prog = lc($rc_args{'nuvexport'}{'export_prog'})) {
if ($export_prog !~ /(?:ffmpeg|transcode)$/) {
print "Unknown export_prog in nuvexportrc: $export_prog\n\n";
exit;
}
}
else {
$export_prog = find_program('ffmpeg') ? 'ffmpeg' : 'transcode';
}
}

# Debug mode?
our $DEBUG;

Expand Down Expand Up @@ -106,6 +167,24 @@ package nuv_export::cli;
return defined($args{$arg}) ? $args{$arg} : $default;
}

# Retrieve the value of a nuvexportrc argument
sub rc_arg {
my $arg = lc(shift);
my $package = lc(shift or (caller())[0]);
# Remove an unused package parent name, and any leftovers from $self
$package =~ s/^export:://;
$package =~ s/=.+?$//;
# Scan the package from child to parent, looking for matches
while ($package) {
return $rc_args{$package}{$arg} if (defined $rc_args{$package}{$arg});
last unless ($package =~ s/::.+?$//);
}
# Finally, try "generic"
return $rc_args{'generic'}{$arg} if (defined $rc_args{'generic'}{$arg});
# Lastly, try "nuvexport" (or just return undef)
return $rc_args{'nuvexport'}{$arg};
}

1; #return true

# vim:ts=4:sw=4:ai:et:si:sts=4
55 changes: 34 additions & 21 deletions trunk/nuv_export/shared_utils.pm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/perl -w
#Last Updated: 2005.02.16 (xris)
#Last Updated: 2005.02.25 (xris)
#
# nuv_export::shared_utils
#
Expand All @@ -17,7 +17,7 @@ package nuv_export::shared_utils;
our @EXPORT = qw/ &clear &find_program &shell_escape
&wrap &wipe_tmpfiles
&system &mkdir
@Exporters
@Exporters @episodes
$DEBUG $NICE
$num_cpus $is_child
@tmpfiles %children
Expand All @@ -26,6 +26,7 @@ package nuv_export::shared_utils;

# Variables that we export so all other modules can share them
our @Exporters; # A list of the various exporters
our @episodes; # A list of the requested episodes
our $is_child = 0; # This is set to 1 after forking to a new process
our @tmpfiles; # Keep track of temporary files, so we can clean them up upon quit
our %children; # Keep track of child pid's so we can kill them off if we quit unexpectedly
Expand Down Expand Up @@ -82,31 +83,43 @@ package nuv_export::shared_utils;
print $DEBUG ? "\n" : $terminal->Tputs('cl');
}

# This searches the path for the specified programs, and returns the lowest-index-value program found
# This searches the path for the specified programs, and returns the
# lowest-index-value program found, caching the results
BEGIN {
my %find_program_cache;
sub find_program {
# Load the programs, and get a count of the priorities
my (%programs, $num_programs);
foreach my $program (@_) {
$programs{$program} = ++$num_programs;
}
# No programs requested?
return undef unless ($num_programs > 0);
# Search for the program(s)
my %found;
foreach my $path (split(/:/, $ENV{'PATH'}), '.') {
foreach my $program (keys %programs) {
if (-e "$path/$program" && (!$found{'name'} || $programs{$program} < $programs{$found{'name'}})) {
$found{'name'} = $program;
$found{'path'} = $path;
# Get the hash id
my $hash_id = join("\n", @_);
# No cache?
if (!defined($find_program_cache{$hash_id})) {
# Load the programs, and get a count of the priorities
my (%programs, $num_programs);
foreach my $program (@_) {
$programs{$program} = ++$num_programs;
}
# No programs requested?
return undef unless ($num_programs > 0);
# Search for the program(s)
my %found;
foreach my $path (split(/:/, $ENV{'PATH'}), '.') {
foreach my $program (keys %programs) {
if (-e "$path/$program" && (!$found{'name'} || $programs{$program} < $programs{$found{'name'}})) {
$found{'name'} = $program;
$found{'path'} = $path;
}
# Leave early if we found the highest priority program
last if ($found{'name'} && $programs{$found{'name'}} == 1);
}
# Leave early if we found the highest priority program
last if ($found{'name'} && $programs{$found{'name'}} == 1);
}
# Set the cache
$find_program_cache{$hash_id} = ($found{'path'} && $found{'name'})
? $found{'path'}.'/'.$found{'name'}
: '';
}
# Return
return undef unless ($found{'path'} && $found{'name'});
return $found{'path'}.'/'.$found{'name'};
return $find_program_cache{$hash_id};
}
}

# Escape a parameter for safe use in a commandline call
sub shell_escape {
Expand Down
35 changes: 23 additions & 12 deletions trunk/nuv_export/ui.pm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/perl -w
#Last Updated: 2005.02.16 (xris)
#Last Updated: 2005.02.23 (xris)
#
# nuvexport::ui
#
Expand All @@ -9,6 +9,7 @@
package nuv_export::ui;

use File::Path;
use English;

# Load the myth and nuv utilities, and make sure we're connected to the database
use nuv_export::shared_utils;
Expand Down Expand Up @@ -366,7 +367,7 @@ package nuv_export::ui;
# No need?
return undef unless (arg('noserver') || arg('path'));
# Grab a path from the commandline?
my $path = (arg('path') or '');
my $path = (shift or arg('path') or '.');
$path =~ s/\/+$//s;
if ($is_cli) {
# Need a pathname
Expand All @@ -379,32 +380,32 @@ package nuv_export::ui;
die "$path isn't writable.\n" unless (-w $path);
}
# Where are we saving the files to?
until ($path && -d $path && -w $path) {
while (1) {
# Query
if (!$path) {
$path = query_text('Where would you like to export the files to?', 'string', '.');;
$path =~ s/\/+$//s;
}
$path = query_text('Where would you like to export the files to?', 'string', $path);
$path =~ s/\/+$//s;
# Doesn't exist - query the user to create it
if (!-e $path) {
my $create = query_text("$path doesn't exist. Create it?", 'yesno', 'Yes');
if ($create) {
mkpath($path, 1, 0711) or die "Couldn't create $path: $!\n\n";
}
else {
$path = undef;
next;
}
}
# Make sure this is a valid directory
elsif (!-d $path) {
print "$path exists, but is not a directory.\n";
$path = undef;
next;
}
# Not writable
elsif (!-w $path) {
print "$path isn't writable.\n";
$path = undef;
next;
}
# All done
last;
}
return $path;
}
Expand All @@ -414,7 +415,17 @@ package nuv_export::ui;
my $type = shift;
my $default = shift;
my $default_extra = shift;
my $return = undef;
my $return = undef;
# Clean up boolean default values
if ($type =~ /yes.*no|bool/i) {
$type = 'yesno';
if (!$default || $default =~ /^\W*[nf0]/i) {
$default = 'No';
}
else {
$default = 'Yes';
}
}
# Loop until we get a valid response
while (1) {
# Ask the question, get the answer
Expand All @@ -428,7 +439,7 @@ package nuv_export::ui;
$return = $default;
}
# Looking for a boolean/yesno response?
if ($type =~ /yes.*no|bool/i) {
if ($type eq 'yesno') {
return $return =~ /^\W*[nf0]/i ? 0 : 1;
}
# Looking for an integer?
Expand Down
44 changes: 27 additions & 17 deletions trunk/nuvexport
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/perl -w
# Last Updated: 2005.02.16 (xris)
# Last Updated: 2005.02.25 (xris)

# Version
$VERSION = '0.2 cvs20050221';
Expand Down Expand Up @@ -34,47 +34,57 @@

# Load the exporters based on which suite was selected above
if ($export_prog eq 'transcode') {
find_program('transcode')
or die "You need transcode in order to use nuvexport in --transcode mode\n";
# transcode - doesn't seem to work for many MPEG recordings these days
require export::transcode::XviD;
push @Exporters, export::transcode::XviD->new;
require export::transcode::SVCD;
push @Exporters, export::transcode::SVCD->new;
require export::transcode::VCD;
push @Exporters, export::transcode::VCD->new;
require export::transcode::DVCD;
push @Exporters, export::transcode::DVCD->new;
require export::transcode::DVD;
push @Exporters, export::transcode::DVD->new;
}
elsif ($export_prog eq 'ffmpeg') {
find_program('ffmpeg')
or die "You need ffmpeg in order to use nuvexport in --ffmpeg mode\n";
# ffmpeg - seems to work better and is the default
require export::ffmpeg::XviD;
push @Exporters, export::ffmpeg::XviD->new;
require export::ffmpeg::SVCD;
push @Exporters, export::ffmpeg::SVCD->new;
require export::ffmpeg::VCD;
push @Exporters, export::ffmpeg::VCD->new;
require export::ffmpeg::DVCD;
push @Exporters, export::ffmpeg::DVCD->new;
require export::ffmpeg::DVD;
push @Exporters, export::ffmpeg::DVD->new;
require export::ffmpeg::DivX;
push @Exporters, export::ffmpeg::DivX->new;
require export::ffmpeg::ASF;
push @Exporters, export::ffmpeg::ASF->new;
require export::ffmpeg::MP3;
push @Exporters, export::ffmpeg::MP3->new;
}

# Load the other export modules
require export::MPEG2_cut;
push @Exporters, export::MPEG2_cut->new;
require export::NUV_SQL;
push @Exporters, export::NUV_SQL->new;

# Load the ui
load_cli_args();

# Now that we've loaded the cli args, we can define the exporters
if ($export_prog eq 'transcode') {
push @Exporters, export::transcode::XviD->new;
push @Exporters, export::transcode::SVCD->new;
push @Exporters, export::transcode::VCD->new;
push @Exporters, export::transcode::DVCD->new;
push @Exporters, export::transcode::DVD->new;
}
elsif ($export_prog eq 'ffmpeg') {
push @Exporters, export::ffmpeg::XviD->new;
push @Exporters, export::ffmpeg::SVCD->new;
push @Exporters, export::ffmpeg::VCD->new;
push @Exporters, export::ffmpeg::DVCD->new;
push @Exporters, export::ffmpeg::DVD->new;
push @Exporters, export::ffmpeg::DivX->new;
push @Exporters, export::ffmpeg::ASF->new;
push @Exporters, export::ffmpeg::MP3->new;
}
push @Exporters, export::MPEG2_cut->new;
push @Exporters, export::NUV_SQL->new;

# Show the version?
if (arg('version')) {
print "nuvexport version: $VERSION\n";
Expand All @@ -90,7 +100,7 @@
load_recordings();

# Load episodes from the commandline (and display/quit if this is search-only)
my @episodes = load_cli_episodes();
@episodes = load_cli_episodes();

# Which exporter to use
my $exporter = query_exporters($export_prog);
Expand Down
98 changes: 98 additions & 0 deletions trunk/nuvexportrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#
# nuvexportrc:
#
# This file contains the configuration for nuvexport, and should be installed
# as /etc/nuvexportrc or ~/.nuvexportrc (if you use both, the one in your
# home directory will take precedence).
#
# The config in this file likely will NOT work, which is why this file has
# been left out of the makefile and rpm for the time being.
#

#
# Anything placed within the <nuvexport> section
#
<nuvexport>

#
# Set export_prog to ffmpeg or transcode, depending on your preference of
# program for exports. This is equivalent to --ffmpeg or --transcode.
#
export_prog=transcode

#
# Any other parameters set in this file are equivalent to using the equivalent
# setting as a commandline option. For boolean options like --deinterlace
# (--nodeinterlace), use deinterlace=yes (or no, true or false) instead.
# Actual commandline options will override anything in this file.
#

#
# Preferred mode -- if you don't set this, nuvexport will ask you what you
# would like to do. Use --mode or any of the mode symlinks (like
# nuvexport-xvid) to override.
#
# mode=xvid

#
# Setting underscores to yes will convert whitespace in filenames to an
# underscore character (which some people seem to prefer)
underscores=no

</nuvexport>

#
# The sections below work as above, with each more specific section overriding
# the more generic.
#

<generic>

path = /home/xris/Video

use_cutlist = yes
multipass = yes

noise_reduction = yes
deinterlace = yes
crop = yes

</generic>


<ffmpeg>
</ffmpeg>

<ffmpeg::XviD>

vbr = yes # Enable vbr to get the multipass/quantisation options
# (enabling multipass or quantisation automatically enables vbr)
multipass = yes # You get either multipass or quantisation; multipass will override
quantisation = 6 # 4 through 6 is probably right... 1..31 are allowed (lower is better quality)

a_bitrate = 128 # Audio bitrate of 128 kbps
v_bitrate = 960 # Remember, quantisation overrides video bitrate

width = 624 # Height adjusts automatically to width, according to aspect ratio
height = auto

</ffmpeg::XviD>

<transcode>
</transcode>

<transcode::XviD>

vbr = yes # Enable vbr to get the multipass/quantisation options
# (enabling multipass or quantisation automatically enables vbr)
multipass = yes # You get either multipass or quantisation; multipass will override
quantisation = 6 # 4 through 6 is probably right... 1..31 are allowed (lower is better quality)

a_bitrate = 128 # Audio bitrate of 128 kbps
v_bitrate = 960 # Remember, quantisation overrides video bitrate

width = 624 # Height adjusts automatically to width, according to aspect ratio
height = auto

</transcode::XviD>