Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Reworked ffmpeg exporters to work with mythffmpeg

Although there is doubtless more cleanup to do as a result of this, nuvexport
now uses the ffmpeg build provided by mythtv itself as part of it builds.  This
is as of MythTV/mythtv@8c6de46
All of the ffmpeg exporters have been tested with this setup.

Additionally, sox is now used to downsample 6-channel audio to 2-channel before
encoding.  This should fix the reported problems of encoding from AC-3 audio.
I may refactor the dependency later so it only checks for sox if it's needed
for the particular job at hand.

Split the "MP4 (iPod)" into two exporters: MP4 and H.264, as it is confusing
to look for H.264 buried inside MP4.

Fixes #9199.  Fixes #9205.
  • Loading branch information...
commit c18508f20448077762d23ab9207c5eb643324dc0 1 parent 240785b
@Beirdo Beirdo authored
View
1  Makefile
@@ -17,6 +17,7 @@ EXPORT_MODULES = export/generic.pm \
export/ffmpeg/DVD.pm \
export/ffmpeg/PSP.pm \
export/ffmpeg/MP4.pm \
+ export/ffmpeg/H264.pm \
export/mencoder/XviD.pm \
export/mencoder/H264MP3.pm \
export/mencoder/H264AAC.pm
View
78 export/ffmpeg.pm
@@ -47,6 +47,9 @@ package export::ffmpeg;
# Make sure we have yuvdenoise
my $yuvdenoise = find_program('yuvdenoise')
or push @{$self->{'errors'}}, 'You need yuvdenoise (part of mjpegtools) to use this exporter.';
+ # Make sure we have sox
+ my $sox = find_program('sox')
+ or push @{$self->{'errors'}}, 'You need sox to use this exporter.';
# Check the yuvdenoise version
if (!defined $self->{'denoise_vmaj'}) {
$data = `cat /dev/null | yuvdenoise 2>&1`;
@@ -191,23 +194,28 @@ package export::ffmpeg;
$mythtranscode .= ' --honorcutlist' if ($self->{'use_cutlist'});
$mythtranscode .= ' --fifosync' if ($self->{'audioonly'} || $firstpass);
+ my $audiofifo = "/tmp/fifodir_$$/audout";
my $videofifo = "/tmp/fifodir_$$/vidout";
my $videotype = 'rawvideo -pix_fmt yuv420p';
my $crop_w;
my $crop_h;
my $pad_w;
my $pad_h;
+ my $scale_w;
+ my $scale_h;
my $height;
my $width;
+ my @filters;
+ my $sox;
# Standard encodes
if (!$self->{'audioonly'}) {
# Do noise reduction -- ffmpeg's -nr flag doesn't seem to do anything other than prevent denoise from working
if ($self->{'noise_reduction'}) {
- $ffmpeg .= "$NICE ffmpeg -f rawvideo";
+ $ffmpeg .= "$NICE mythffmpeg -f rawvideo";
$ffmpeg .= ' -s ' . $episode->{'finfo'}{'width'} . 'x' . $episode->{'finfo'}{'height'};
$ffmpeg .= ' -r ' . $episode->{'finfo'}{'fps'};
- $ffmpeg .= " -i /tmp/fifodir_$$/vidout -f yuv4mpegpipe -";
+ $ffmpeg .= " -i $videofifo -f yuv4mpegpipe -";
$ffmpeg .= ' 2> /dev/null | ';
$ffmpeg .= "$NICE yuvdenoise";
if ($self->{'denoise_vmaj'} < 1.6 || ($self->{'denoise_vmaj'} == 1.6 && $self->{'denoise_vmin'} < 3)) {
@@ -226,16 +234,33 @@ package export::ffmpeg;
}
}
+ # If we have 6-channel audio, and want 2-channel, we need to use sox as
+ # ffmpeg is retarded and won't/can't do it
+ if ((!$firstpass || $self->{'audioonly'}) &&
+ $episode->{'finfo'}{'audio_channels'} > 2) {
+ my $newaudiofifo = "/tmp/fifodir_$$/audout2";
+ $sox = "$NICE sox --single-threaded -t raw -e signed -2"
+ . " -c " . $episode->{'finfo'}{'audio_channels'}
+ . " -r " . $episode->{'finfo'}{'audio_sample_rate'}
+ . " $audiofifo -t raw -e signed -2 -c 2"
+ . " -r " . $episode->{'finfo'}{'audio_sample_rate'}
+ . " $newaudiofifo"
+ . " remix -m 1,4v0.5,2v0.7 3,5v0.5,2v0.7";
+ $audiofifo = $newaudiofifo;
+ }
+
# Start the ffmpeg command
- $ffmpeg .= "$NICE ffmpeg";
+ $ffmpeg .= "$NICE mythffmpeg";
if ($num_cpus > 1) {
$ffmpeg .= ' -threads '.($num_cpus);
}
- $ffmpeg .= ' -y -f '.($Config{'byteorder'} == 4321 ? 's16be' : 's16le')
- .' -ar ' . $episode->{'finfo'}{'audio_sample_rate'}
- .' -ac ' . $episode->{'finfo'}{'audio_channels'};
+ $ffmpeg .= ' -y';
if (!$firstpass) {
- $ffmpeg .= " -i /tmp/fifodir_$$/audout";
+ $ffmpeg .=' -f '.($Config{'byteorder'} == 4321 ? 's16be' : 's16le')
+ .' -ar ' . $episode->{'finfo'}{'audio_sample_rate'}
+# .' -ac ' . $episode->{'finfo'}{'audio_channels'};
+ .' -ac 2';
+ $ffmpeg .= " -i $audiofifo";
}
if (!$self->{'audioonly'}) {
$ffmpeg .= " -f $videotype"
@@ -246,6 +271,9 @@ package export::ffmpeg;
$self->{'out_aspect'} ||= $episode->{'finfo'}{'aspect_f'};
+ $ffmpeg .= ' -aspect ' . $self->{'out_aspect'}
+ .' -r ' . $self->{'out_fps'};
+
# The output is actually a stretched/anamorphic aspect ratio
# (like 480x480 for SVCD, which is 4:3)
if ($self->{'aspect_stretched'}) {
@@ -274,8 +302,8 @@ package export::ffmpeg;
}
}
- $ffmpeg .= ' -aspect ' . $self->{'out_aspect'}
- .' -r ' . $self->{'out_fps'};
+ $scale_w = $width - (2 * $pad_w);
+ $scale_h = $height - (2 * $pad_h);
# Deinterlace in ffmpeg only if the user wants to
if ($self->val('deinterlace') && !($self->val('noise_reduction') && $self->val('deint_in_yuvdenoise'))) {
@@ -293,23 +321,25 @@ package export::ffmpeg;
$b-- if ($b > 0 && $b % 2);
$l-- if ($l > 0 && $l % 2);
# crop
- $ffmpeg .= " -croptop $t -cropright $r"
- ." -cropbottom $b -cropleft $l" if ($t || $r || $b || $l);
+ $crop_w = $episode->{'finfo'}{'width'} - $r - $l;
+ $crop_h = $episode->{'finfo'}{'height'} - $b - $t;
+ push @filters, "crop=$l:$t:$crop_w:$crop_h" if ($t || $r || $b || $l);
}
# Letter/Pillarboxing as appropriate
- if ($pad_h) {
- $ffmpeg .= " -padtop $pad_h -padbottom $pad_h";
- }
- if ($pad_w) {
- $ffmpeg .= " -padleft $pad_w -padright $pad_w";
- }
- $ffmpeg .= " -s ${width}x$height";
+ push @filters, "scale=$scale_w:$scale_h";
+ push @filters, "pad=$width:$height:$pad_w:$pad_h:black" if ($pad_h | $pad_w);
+ push @filters, "pixelaspect=1";
+ push @filters, "slicify";
+
+ # Add in the filters
+ $ffmpeg .= " -vf " . join(",", @filters) if ($#filters != -1);
}
# Add any additional settings from the child module
$ffmpeg .= ' '.$self->{'ffmpeg_xtra'};
+
# Output directory set to null means the first pass of a multipass
if ($firstpass || !$self->{'path'} || $self->{'path'} =~ /^\/dev\/null\b/) {
$ffmpeg .= ' /dev/null';
@@ -319,7 +349,8 @@ package export::ffmpeg;
$ffmpeg .= ' '.shell_escape($self->get_outfile($episode, $suffix));
}
# ffmpeg pids
- my ($mythtrans_pid, $ffmpeg_pid, $mythtrans_h, $ffmpeg_h);
+ my ($mythtrans_pid, $sox_pid, $ffmpeg_pid, $mythtrans_h, $sox_h,
+ $ffmpeg_h);
# Create a directory for mythtranscode's fifo's
mkdir("/tmp/fifodir_$$/", 0755) or die "Can't create /tmp/fifodir_$$/: $!\n\n";
@@ -328,6 +359,15 @@ package export::ffmpeg;
fifos_wait("/tmp/fifodir_$$/", $mythtrans_pid, $mythtrans_h);
push @tmpfiles, "/tmp/fifodir_$$", "/tmp/fifodir_$$/audout", "/tmp/fifodir_$$/vidout";
+ # Run sox if needed
+ if ((!$firstpass || $self->{'audioonly'}) &&
+ ($episode->{'finfo'}{'audio_channels'} > 2)) {
+ POSIX::mkfifo( "/tmp/fifodir_$$/audout2", 0644 );
+ push @tmpfiles, "/tmp/fifodir_$$/audout2";
+ ($sox_pid, $sox_h) = fork_command("$sox 2>&1");
+ $children{$sox_pid} = 'sox' if ($sox_pid);
+ }
+
# For multipass encodes, we don't need the audio on the first pass
if ($self->{'audioonly'}) {
my ($cat_pid, $cat_h) = fork_command("cat /tmp/fifodir_$$/vidout > /dev/null");
View
265 export/ffmpeg/H264.pm
@@ -0,0 +1,265 @@
+# vim:ts=4:sw=4:ai:et:si:sts=4
+#
+# ffmpeg-based H.264 (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
+#
+
+package export::ffmpeg::H264;
+ 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_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(?:h264|ipodh264)\b/i,
+ 'name' => 'Export to H.264 (including 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_format('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('libx264')) {
+ push @{$self->{'errors'}}, "Your ffmpeg installation doesn't support encoding to 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;
+ }
+
+# 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 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'));
+ }
+ # 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 (!defined $self->val('mp4_fps')) {
+ $self->{'mp4_fps'} = "auto";
+ }
+
+ 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 = 'libx264';
+
+ # Build the common ffmpeg string
+ my $ffmpeg_xtra =
+ ' -vcodec '.$codec
+ .$self->param('bit_rate', $self->{'v_bitrate'})
+ ;
+ # Options required for the codecs separately
+ $ffmpeg_xtra .= ' -level 30'
+ .' -flags loop+slice'
+ .' -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_method umh'
+ ;
+ # 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 (-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',
+ 'x264_2pass.log.mbtree';
+ # Build the ffmpeg string
+ print "First pass...\n";
+ $self->{'ffmpeg_xtra'} = ' -pass 1'
+ .$ffmpeg_xtra
+ .' -f mp4'
+ .' -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
+ $ffmpeg_xtra .= ' -refs '.($self->val('ipod') ? 2 : 7)
+ .' -subq 7'
+ .' -partitions parti4x4+parti8x8+partp4x4+partp8x8+partb8x8'
+ .' -flags2 +bpyramid+wpred+mixed_refs+dct8x8'
+ .' -me_range 21'
+ .' -trellis 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"
+ ." -strict experimental" if ($acodec eq "aac")
+ .$self->param('ab', $self->{'a_bitrate'});
+ # Execute the (final pass) encode
+ $self->SUPER::export($episode, '.mp4');
+ }
+
+1; #return true
+
View
1  export/ffmpeg/MP3.pm
@@ -79,6 +79,7 @@ package export::ffmpeg::MP3;
my $episode = shift;
# Build the ffmpeg string
$self->{'ffmpeg_xtra'} = $self->param('ab', $self->val('bitrate'))
+ .$self->param('ac', 2)
.' -acodec '
.($self->can_encode('libmp3lame') ? 'libmp3lame' : 'mp3')
.' -f mp3';
View
102 export/ffmpeg/MP4.pm
@@ -6,12 +6,6 @@
# http://rob.opendot.cl/index.php?active=3&subactive=1
# http://videotranscoding.wikispaces.com/EncodeForIPodorPSP
#
-# @url $URL$
-# @date $Date$
-# @version $Revision$
-# @author $Author$
-# @copyright Silicon Mechanics
-#
package export::ffmpeg::MP4;
use base 'export::ffmpeg';
@@ -27,7 +21,6 @@ package export::ffmpeg::MP4;
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.');
@@ -70,8 +63,8 @@ package export::ffmpeg::MP4;
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.";
+ if (!$self->can_encode('mpeg4')) {
+ push @{$self->{'errors'}}, "Your ffmpeg installation doesn't support encoding to mpeg4 video.";
}
# Any errors? disable this function
$self->{'enabled'} = 0 if ($self->{'errors'} && @{$self->{'errors'}} > 0);
@@ -88,13 +81,7 @@ package export::ffmpeg::MP4;
$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
@@ -112,21 +99,6 @@ package export::ffmpeg::MP4;
$self->{'ipod'} = query_text('Enable iPod compatibility?',
'yesno',
$self->val('ipod'));
- # Video codec
- 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";
- }
# Video bitrate options
$self->{'vbr'} = query_text('Variable bitrate video?',
'yesno',
@@ -183,6 +155,11 @@ package export::ffmpeg::MP4;
$self->{'aspect_stretched'} = 1;
# Framerate
my $standard = ($episode->{'finfo'}{'fps'} =~ /^2(?:5|4\.9)/) ? 'PAL' : 'NTSC';
+
+ if (!defined $self->val('mp4_fps')) {
+ $self->{'mp4_fps'} = "auto";
+ }
+
if ($standard eq 'PAL') {
$self->{'out_fps'} = 25;
}
@@ -201,39 +178,19 @@ package export::ffmpeg::MP4;
$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';
- }
+ my $codec = 'mpeg4';
+
# Build the common ffmpeg string
my $ffmpeg_xtra =
' -vcodec '.$codec
.$self->param('bit_rate', $self->{'v_bitrate'})
;
# Options required for the codecs separately
- if ($self->{'mp4_codec'} eq 'h264') {
- $ffmpeg_xtra .= ' -level 30'
- .' -flags loop+slice'
- .' -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_method umh'
- ;
- }
- else {
- $ffmpeg_xtra .= ' -flags +mv4+loop+aic'
- .' -trellis 1'
- .' -mbd 1'
- .' -cmp 2 -subcmp 2'
- ;
- }
+ $ffmpeg_xtra .= ' -flags +mv4+loop+aic'
+ .' -trellis 1'
+ .' -mbd 1'
+ .' -cmp 2 -subcmp 2'
+ ;
# Some shared options
if ($self->{'multipass'} || $self->{'vbr'}) {
$ffmpeg_xtra .= $self->param('qcompress', 0.6)
@@ -243,28 +200,13 @@ package export::ffmpeg::MP4;
}
# 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',
- 'x264_2pass.log.mbtree',
- 'ffmpeg2pass-0.log';
+ push @tmpfiles, '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";
@@ -277,24 +219,12 @@ package export::ffmpeg::MP4;
$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'
- .' -me_range 21'
- .' -trellis 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"
+ ." -strict experimental" if ($acodec eq "aac")
.$self->param('ab', $self->{'a_bitrate'});
# Execute the (final pass) encode
$self->SUPER::export($episode, '.mp4');
View
17 export/ffmpeg/PSP.pm
@@ -172,19 +172,22 @@ package export::ffmpeg::PSP;
.' -bufsize 65535'
.$self->param('ab', 32)
.' -acodec '.$acodec
+ .' -strict experimental' if ($acodec eq "aac")
." -f psp";
# Execute the parent method
$self->SUPER::export($episode, '.MP4');
# Make the thumbnail if needed
if ($self->{'psp_thumbnail'}) {
- my $ffmpeg = find_program('ffmpeg')
- or die("where is ffmpeg, we had it when we did an ffmpeg_init?");
-
- $ffmpeg .= ' -y -i ' .shell_escape($self->get_outfile($episode, '.MP4',1))
- .' -s 160x90 -padtop 16 -padbottom 14 -r 1 -t 1'
- .' -ss 7:00.00 -an -f mjpeg '
- .shell_escape($self->get_outfile($episode, '.THM'));
+ my $ffmpeg = find_program('mythffmpeg')
+ or die("where is mythffmpeg, we had it when we did an ffmpeg_init?");
+
+ $ffmpeg .= ' -y -i '
+ .shell_escape($self->get_outfile($episode, '.MP4',1))
+ .' -ss 420 -vframes 1'
+ .' -vf scale=160:90,pad=160:120:0:16:black'
+ .' -an -f mjpeg '
+ .shell_escape($self->get_outfile($episode, '.THM'));
`$ffmpeg` unless ($DEBUG);
if ($DEBUG) {
View
6 nuvexport
@@ -53,8 +53,8 @@
# Load the exporters based on which suite was selected above
if ($export_prog eq 'ffmpeg') {
- find_program('ffmpeg')
- or die "You need ffmpeg in order to use nuvexport in --ffmpeg mode\n";
+ find_program('mythffmpeg')
+ or die "You need mythffmpeg in order to use nuvexport in --ffmpeg mode\n";
# ffmpeg - seems to work better and is the default
require export::ffmpeg::XviD;
require export::ffmpeg::DVD;
@@ -63,6 +63,7 @@
require export::ffmpeg::MP3;
require export::ffmpeg::PSP;
require export::ffmpeg::MP4;
+ require export::ffmpeg::H264;
}
elsif ($export_prog eq 'mencoder') {
find_program('mencoder')
@@ -89,6 +90,7 @@
push @Exporters, export::ffmpeg::MP3->new;
push @Exporters, export::ffmpeg::PSP->new;
push @Exporters, export::ffmpeg::MP4->new;
+ push @Exporters, export::ffmpeg::H264->new;
}
elsif ($export_prog eq 'mencoder') {
push @Exporters, export::mencoder::XviD->new;
View
12 nuvexportrc
@@ -337,18 +337,6 @@
<ffmpeg::MP4>
#
-# Codec to use (mpeg4 or h264). Please note that h264 support requires the
-# SVN version of ffmpeg (not CVS!). In fact, even the mpeg4 codec works
-# better with the SVN version.
-#
-# Note: The h.264 files exported by nuvexport seem to play fine on
-# ipods, but lack the atom necessary to be recognized by iTunes, so you
-# will have to find other means to get the exports onto your ipod (gtkpod
-# works great).
-#
- mp4_codec = h264
-
-#
# Framerate to use: auto, 25, 23.97, 29.97. PAL will always be 25 fps,
# and auto will set 29.97 for everything over 320x288 and 23.97 for the
# rest.
Please sign in to comment.
Something went wrong with that request. Please try again.