add --letterbox and --audio options

This commit is contained in:
Brooke Vibber 2023-01-15 10:25:47 -08:00
parent af0592e892
commit 868f2d9d4f
1 changed files with 61 additions and 24 deletions

View File

@ -2,8 +2,8 @@
<?php <?php
// Squishes given video input into sub-4000kb .mp4 // Squishes given video input into sub-4000kb .mp4
// Crops to 16:9 // Crops or pads to 16:9 (crop default; --letterbox to pad)
// Strips audio // Strips audio (to override, pass --audio for 96 kbps AAC)
// HDR to SDR tonemapping // HDR to SDR tonemapping
// Picks bitrate to match // Picks bitrate to match
// Picks resolution based on bitrate target // Picks resolution based on bitrate target
@ -11,12 +11,26 @@
$args = $_SERVER['argv']; $args = $_SERVER['argv'];
$self = array_shift( $args ); $self = array_shift( $args );
$options = [
'letterbox' => false,
'audio' => false,
];
while ( count( $args ) > 0 && substr( $args[0], 0, 2 ) == '--' ) {
$option = substr( array_shift( $args ), 2 );
$options[$option] = true;
}
if ( count ( $args ) < 2 ) { if ( count ( $args ) < 2 ) {
die( "Usage: $self <srcfile.mp4> <destfile.mp4>\n" ); die(
"Usage: $self [options...] <srcfile.mp4> <destfile.mp4>\n" .
"Options:\n" .
" --letterbox pad instead of cropping\n" .
" --audio include audio\n"
);
} }
[ $src, $dest ] = $args; [ $src, $dest ] = $args;
convert( $src, $dest ); convert( $src, $dest, $options );
exit(0); exit(0);
// //
@ -65,7 +79,7 @@ function evenize( $n ) {
return $n; return $n;
} }
function convert( $src, $dest ) { function convert( $src, $dest, $options ) {
$maxBits = 4000 * 1000 * 8; // fit in 4Mb $maxBits = 4000 * 1000 * 8; // fit in 4Mb
$maxBits = $maxBits * 7 / 8; // leave some headroom $maxBits = $maxBits * 7 / 8; // leave some headroom
@ -84,18 +98,34 @@ function convert( $src, $dest ) {
$bitrate = floor( $maxBits / $duration ); $bitrate = floor( $maxBits / $duration );
if ( $options[ 'audio' ] ) {
$audioBitrate = 96 * 1000;
$audio = [ '-b:a', $audioBitrate ];
$bitrate -= $audioBitrate;
} else {
$audio = [ '-an' ];
}
$mbits = 1000 * 1000; $mbits = 1000 * 1000;
if ( $bitrate < 2 * $mbits ) { if ( $bitrate < 2 * $mbits ) {
$cropWidth = 854; $frameWidth = 854;
$scaleHeight = 480; $frameHeight = 480;
} else if ( $bitrate <= 4 * $mbits ) { } else if ( $bitrate <= 4 * $mbits ) {
$cropWidth = 1280; $frameWidth = 1280;
$scaleHeight = 720; $frameHeight = 720;
} else { } else {
$cropWidth = 1920; $frameWidth = 1920;
$scaleHeight = 1080; $frameHeight = 1080;
}
if ( $options['letterbox'] ) {
$scaleWidth = $frameWidth;
$scaleHeight = evenize( $height * $frameWidth / $width );
} else {
$scaleHeight = $frameHeight;
$scaleWidth = evenize( $width * $frameHeight / $height );
} }
$scaleWidth = evenize( $width * $scaleHeight / $height );
$filters = [ "scale=w=$scaleWidth:h=$scaleHeight" ]; $filters = [ "scale=w=$scaleWidth:h=$scaleHeight" ];
if ( $hdr ) { if ( $hdr ) {
@ -104,7 +134,12 @@ function convert( $src, $dest ) {
$filters[] = "zscale=t=bt709:m=bt709:r=full"; $filters[] = "zscale=t=bt709:m=bt709:r=full";
} }
$filters[] = "format=yuv420p"; $filters[] = "format=yuv420p";
$filters[] = "crop=w=$cropWidth"; if ( $options['letterbox'] ) {
$offset = round( ( $frameHeight - $scaleHeight) / 2 );
$filters[] = "pad=h=$frameHeight:y=$offset";
} else {
$filters[] = "crop=w=$frameWidth";
}
$vf = implode( ',', $filters ); $vf = implode( ',', $filters );
run( 'ffmpeg', [ run( 'ffmpeg', [
@ -119,17 +154,19 @@ function convert( $src, $dest ) {
'-an', '-an',
'-y', '/dev/null' '-y', '/dev/null'
] ); ] );
run( 'ffmpeg', [ run( 'ffmpeg',
'-i', $src, array_merge( [
'-vf', $vf, '-i', $src,
'-c:v', 'libx264', '-vf', $vf,
'-b:v', $bitrate, '-c:v', 'libx264',
'-preset', 'veryslow', '-b:v', $bitrate,
'-pass', '2', '-preset', 'veryslow',
'-g', $keyframeInt, '-pass', '2',
'-an', '-g', $keyframeInt,
'-y', $dest ], $audio, [
] ); '-y', $dest
] )
);
} }
/* /*