From f5681911497798ddd74e9ac46c04ca9923a7805b Mon Sep 17 00:00:00 2001
From: Cecil Hugh Watson <knoppmyth@gmail.com>
Date: Sun, 19 Jul 2009 16:48:57 -0700
Subject: nuvexport:modification to work with newer FFMPEG.

---
 abs/core-testing/nuvexport/MP4.pm   | 316 ++++++++++++++++++++++++++++++++++++
 abs/core-testing/nuvexport/PKGBUILD |   5 +-
 2 files changed, 319 insertions(+), 2 deletions(-)
 create mode 100755 abs/core-testing/nuvexport/MP4.pm

diff --git a/abs/core-testing/nuvexport/MP4.pm b/abs/core-testing/nuvexport/MP4.pm
new file mode 100755
index 0000000..e13d44b
--- /dev/null
+++ b/abs/core-testing/nuvexport/MP4.pm
@@ -0,0 +1,316 @@
+#!/usr/bin/perl -w
+#
+# ffmpeg-based MP4 (iPod) video module for nuvexport.
+#
+# Many thanks to cartman in #ffmpeg, and for the instructions at
+# http://rob.opendot.cl/index.php?active=3&subactive=1
+# http://videotranscoding.wikispaces.com/EncodeForIPodorPSP
+#
+# @url       $URL: svn+ssh://xris@svn.mythtv.org/var/lib/svn/trunk/mythextras/nuvexport/export/ffmpeg/MP4.pm $
+# @date      $Date: 2008-02-16 20:54:43 -0800 (Sat, 16 Feb 2008) $
+# @version   $Revision: 16110 $
+# @author    $Author: xris $
+# @copyright Silicon Mechanics
+#
+
+package export::ffmpeg::MP4;
+    use base 'export::ffmpeg';
+
+# Load the myth and nuv utilities, and make sure we're connected to the database
+    use nuv_export::shared_utils;
+    use nuv_export::cli;
+    use nuv_export::ui;
+    use mythtv::recordings;
+
+# Load the following extra parameters from the commandline
+    add_arg('quantisation|q=i', 'Quantisation');
+    add_arg('a_bitrate|a=i',    'Audio bitrate');
+    add_arg('v_bitrate|v=i',    'Video bitrate');
+    add_arg('multipass!',       'Enable two-pass encoding.');
+    add_arg('mp4_codec=s',      'Video codec to use for MP4/iPod video (mpeg4 or h264).');
+    add_arg('mp4_fps=s',        'Framerate to use:  auto, 25, 23.97, 29.97.');
+    add_arg('ipod!',            'Produce ipod-compatible output.');
+
+    sub new {
+        my $class = shift;
+        my $self  = {
+                     'cli'      => qr/\b(?:mp4|ipod)\b/i,
+                     'name'     => 'Export to MP4 (iPod)',
+                     'enabled'  => 1,
+                     'errors'   => [],
+                     'defaults' => {},
+                    };
+        bless($self, $class);
+
+    # Initialize the default parameters
+        $self->load_defaults();
+
+    # 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 ffmpeg
+        $self->init_ffmpeg();
+
+    # Can we even encode mp4?
+        if (!$self->can_encode('mp4')) {
+            push @{$self->{'errors'}}, "Your ffmpeg installation doesn't support encoding to mp4 file formats.";
+        }
+        if (!$self->can_encode('aac') && !$self->can_encode('libfaac')) {
+            push @{$self->{'errors'}}, "Your ffmpeg installation doesn't support encoding to aac audio.";
+        }
+        if (!$self->can_encode('mpeg4') && !$self->can_encode('h264') && !$self->can_encode('libx264')) {
+            push @{$self->{'errors'}}, "Your ffmpeg installation doesn't support encoding to either mpeg4 or h264 video.";
+        }
+    # Any errors?  disable this function
+        $self->{'enabled'} = 0 if ($self->{'errors'} && @{$self->{'errors'}} > 0);
+    # Return
+        return $self;
+    }
+
+# Load default settings
+    sub load_defaults {
+        my $self = shift;
+    # Load the parent module's settings
+        $self->SUPER::load_defaults();
+    # Default settings
+        $self->{'defaults'}{'v_bitrate'}  = 384;
+        $self->{'defaults'}{'a_bitrate'}  = 64;
+        $self->{'defaults'}{'width'}      = 320;
+        $self->{'defaults'}{'mp4_codec'}  = 'mpeg4';
+    # Verify commandline options
+        if ($self->val('mp4_codec') !~ /^(?:mpeg4|h264)$/i) {
+            die "mp4_codec must be either mpeg4 or h264.\n";
+        }
+        $self->{'mp4_codec'} =~ tr/A-Z/a-z/;
+
+    }
+
+# Gather settings from the user
+    sub gather_settings {
+        my $self = shift;
+    # Load the parent module's settings
+        $self->SUPER::gather_settings();
+    # Audio Bitrate
+        $self->{'a_bitrate'} = query_text('Audio bitrate?',
+                                          'int',
+                                          $self->val('a_bitrate'));
+    # Video options
+        if (!$is_cli) {
+        # iPod compatibility mode?
+            $self->{'ipod'} = query_text('Enable iPod compatibility?',
+                                         'yesno',
+                                         $self->val('ipod'));
+        # Video codec
+            if ($self->{'ffmpeg_vers'} eq 'svn') {
+                while (1) {
+                    my $codec = query_text('Video codec (mpeg4 or h264)?',
+                                           'string',
+                                           $self->{'mp4_codec'});
+                    if ($codec =~ /^m/) {
+                        $self->{'mp4_codec'} = 'mpeg4';
+                        last;
+                    }
+                    elsif ($codec =~ /^h/) {
+                        $self->{'mp4_codec'} = 'h264';
+                        last;
+                    }
+                    print "Please choose either mpeg4 or h264\n";
+                }
+            }
+            else {
+                $self->{'mp4_codec'} = 'mpeg4';
+                print "Using the mpeg4 codec (h.264 mp4/ipod encoding requires the svn version of ffmpeg.)\n";
+            }
+        # Video bitrate options
+            $self->{'vbr'} = query_text('Variable bitrate video?',
+                                        'yesno',
+                                        $self->val('vbr'));
+            if ($self->{'vbr'}) {
+                $self->{'multipass'} = query_text('Multi-pass (slower, but better quality)?',
+                                                  'yesno',
+                                                  $self->val('multipass'));
+                if (!$self->{'multipass'}) {
+                    while (1) {
+                        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";
+                        }
+                        elsif ($quantisation > 31) {
+                            print "Too high; please choose a number between 1 and 31\n";
+                        }
+                        else {
+                            $self->{'quantisation'} = $quantisation;
+                            last;
+                        }
+                    }
+                }
+            } else {
+                $self->{'multipass'} = 0;
+            }
+        # Ask the user what video bitrate he/she wants
+            $self->{'v_bitrate'} = query_text('Video bitrate?',
+                                              'int',
+                                              $self->val('v_bitrate'));
+        }
+    # Complain about h264
+        if ($self->{'mp4_codec'} eq 'h264' && $self->{'ffmpeg_vers'} ne 'svn') {
+            die "h.264 mp4/ipod encoding requires the svn version of ffmpeg.\n";
+        }
+    # Loop, in case we need to verify ipod compatibility
+        while (1) {
+        # Query the resolution
+            $self->query_resolution();
+        # Warn about ipod resolution
+            if ($self->val('ipod') && ($self->{'height'} > 480 || $self->{'width'} > 640)) {
+                my $note = "WARNING:  Video larger than 640x480 will not play on an iPod.\n";
+                die $note if ($is_cli);
+                print $note;
+                next;
+            }
+        # Done looping
+            last;
+        }
+    }
+
+    sub export {
+        my $self    = shift;
+        my $episode = shift;
+    # Make sure this is set to anamorphic mode
+        $self->{'aspect_stretched'} = 1;
+    # Framerate
+        my $standard = ($episode->{'finfo'}{'fps'} =~ /^2(?:5|4\.9)/) ? 'PAL' : 'NTSC';
+        if ($standard eq 'PAL') {
+            $self->{'out_fps'} = 25;
+        }
+        elsif ($self->val('mp4_fps') =~ /^23/) {
+            $self->{'out_fps'} = 23.97;
+        }
+        elsif ($self->val('mp4_fps') =~ /^29/) {
+            $self->{'out_fps'} = 29.97;
+        }
+        else {
+            $self->{'out_fps'} = ($self->{'width'} > 320 || $self->{'height'} > 288) ? 29.97 : 23.97;
+        }
+    # Embed the title
+        $safe_title = $episode->{'title'};
+        if ($episode->{'subtitle'} ne 'Untitled') {
+            $safe_title .= ' - '.$episode->{'subtitle'};
+        }
+        my $safe_title = shell_escape($safe_title);
+    # Codec name changes between ffmpeg versions
+        my $codec = $self->{'mp4_codec'};
+        if ($codec eq 'h264' && $self->can_encode('libx264')) {
+            $codec = 'libx264';
+        }
+    # Build the common ffmpeg string
+        my $ffmpeg_xtra  = ' -vcodec '.$codec
+                           .$self->param('bit_rate', $self->{'v_bitrate'})
+    ;###                      ." -title $safe_title";
+    # Options required for the codecs separately
+        if ($self->{'mp4_codec'} eq 'h264') {
+            $ffmpeg_xtra .= ' -level 30'
+	    ###                    .' -loop 1'
+                           .' -g 250 -keyint_min 25'
+                           .' -sc_threshold 40'
+			   ###             .' -rc_eq \'blurCplx^(1-qComp)\''
+                           .$self->param('bit_rate_tolerance', $self->{'v_bitrate'})
+                           .$self->param('rc_max_rate',        1500 - $self->{'a_bitrate'})
+                           .$self->param('rc_buffer_size',     2000)
+                           .$self->param('i_quant_factor',     0.71428572)
+                           .$self->param('b_quant_factor',     0.76923078)
+                           .$self->param('max_b_frames',       0)
+			   ### .' -me umh'   # this will eventually be me_method, but not all ffmpeg versions support it yet
+                           ;
+        }
+        else {
+           $ffmpeg_xtra .= ' -flags +mv4' ## +trell+loop'
+	   ###                      .' -aic 1'
+                          .' -mbd 1'
+                          .' -cmp 2 -subcmp 2'
+                          ;
+        }
+    # Some shared options
+        if ($self->{'multipass'} || $self->{'vbr'}) {
+            $ffmpeg_xtra .= $self->param('qcompress', 0.6)
+                           .$self->param('qmax',      51)
+                           .$self->param('max_qdiff', 4)
+                           ;
+        }
+    # Dual pass?
+        if ($self->{'multipass'}) {
+        # Apparently, the -passlogfile option doesn't work for h264, so we need
+        # to be aware of other processes that might be working in this directory
+            if ($self->{'mp4_codec'} eq 'h264' && (-e 'x264_2pass.log.temp' || -e 'x264_2pass.log')) {
+                die "ffmpeg does not allow us to specify the name of the multi-pass log\n"
+                   ."file, and x264_2pass.log exists in this directory already.  Please\n"
+                   ."wait for the other process to finish, or remove the stale file.\n";
+            }
+        # Add all possible temporary files to the list
+            push @tmpfiles, 'x264_2pass.log',
+                            'x264_2pass.log.temp',
+                            'ffmpeg2pass-0.log';
+        # Build the ffmpeg string
+            print "First pass...\n";
+            $self->{'ffmpeg_xtra'} = ' -pass 1'
+                                    .$ffmpeg_xtra
+                                    .' -f mp4';
+            if ($self->{'mp4_codec'} eq 'h264') {
+                $self->{'ffmpeg_xtra'} .= ' -refs 1 -subq 1'
+                                         .' -trellis 0'
+                                         ;
+            }
+            $self->SUPER::export($episode, '', 1);
+        # Second Pass
+            print "Final pass...\n";
+            $ffmpeg_xtra = ' -pass 2 '
+                          .$ffmpeg_xtra;
+        }
+    # Single Pass
+        else {
+            if ($self->{'vbr'}) {
+                $ffmpeg_xtra .= ' -qmin '.$self->{'quantisation'};
+            }
+        }
+    # Single/final pass options
+        if ($self->{'mp4_codec'} eq 'h264') {
+            $ffmpeg_xtra .= ' -refs '.($self->val('ipod') ? 2 : 7)
+                           .' -subq 7'
+                           .' -partitions parti4x4+parti8x8+partp4x4+partp8x8+partb8x8'
+                           .' -flags2 +bpyramid+wpred+mixed_refs+8x8dct' ##+brdo'
+                           .' -me_range 21'
+                           .' -trellis 2'
+                           .' -chromaoffset 1'
+			   ###         .' -slice 2'
+			   ###         .' -cmp 1'
+                           # These should match the defaults:
+                           .' -deblockalpha 0 -deblockbeta 0'
+                           ;
+        }
+    # Audio codec name changes between ffmpeg versions
+        my $acodec = $self->can_encode('libfaac') ? 'libfaac' : 'aac';
+    # Don't forget the audio, etc.
+        $self->{'ffmpeg_xtra'} = $ffmpeg_xtra
+                                ." -acodec $acodec -ar 48000 -async 1"
+                                .$self->param('ab', $self->{'a_bitrate'});
+    # Execute the (final pass) encode
+        $self->SUPER::export($episode, '.mp4');
+    }
+
+1;  #return true
+
+# vim:ts=4:sw=4:ai:et:si:sts=4
+
diff --git a/abs/core-testing/nuvexport/PKGBUILD b/abs/core-testing/nuvexport/PKGBUILD
index e414b1e..9db2c4e 100644
--- a/abs/core-testing/nuvexport/PKGBUILD
+++ b/abs/core-testing/nuvexport/PKGBUILD
@@ -4,7 +4,7 @@
 pkgname=nuvexport
 pkgver=20080311
 relnum=0.5
-pkgrel=1
+pkgrel=2
 pkgdesc="Export for MythTV nuv files to other formats (DVD/SVCD/DivX,etc.)"
 arch=(i686 x86_64)
 url="http://forevermore.net/files/nuvexport"
@@ -15,7 +15,7 @@ conflicts=()
 replaces=()
 backup=()
 install=
-source=(http://forevermore.net/files/nuvexport/$pkgname-$relnum-0.$pkgver.svn.tar.bz2 $pkgname-ipod-disable.patch)
+source=(http://forevermore.net/files/nuvexport/archive/$pkgname-$relnum-0.$pkgver.svn.tar.bz2 $pkgname-ipod-disable.patch MP4.pm)
 md5sums=('2d0a99623f06394daf3bf8769536d3cd' 'acd2dad9987e68359ead8b0be5e5797c')
 
 build() {
@@ -28,4 +28,5 @@ build() {
   mkdir $startdir/pkg/usr || return 1
   make install || return 1
   sed -i "s|/tmp/fifodir|/var/tmp/fifodir|g" $startdir/pkg/usr/share/nuvexport/export/*.pm || return 1
+  cp $startdir/src/MP4.pm $startdir/pkg/usr/share/nuvexport/export/ffmpeg/MP4.pm
 }
-- 
cgit v0.12