This commit is contained in:
Brooke Vibber 2023-04-09 19:23:42 -07:00
parent 4757720ac4
commit c65e2a49b5

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 or pads to 16:9 (crop default; --letterbox to pad) // Crops or pads to 16:9 (letterbox default; --crop to crop)
// Strips audio (to override, pass --audio for 96 kbps AAC) // Includes stereo audio (to strip, pass --no-audio)
// 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
@ -16,10 +16,10 @@ $maxBytes = 4000 * 1000; // fit in 4MB
$maxBytes = $maxBytes * 15 / 16; // leave some headroom $maxBytes = $maxBytes * 15 / 16; // leave some headroom
$options = [ $options = [
'letterbox' => false, 'crop' => false,
'audio' => false, 'no-audio' => false,
'exposure' => '0', 'exposure' => '-0.5', // half stop down
'peak' => '10000', 'peak' => '1000', // '10000' is max
'fps' => '60', 'fps' => '60',
'size' => $maxBytes, 'size' => $maxBytes,
'quality' => 0.75, 'quality' => 0.75,
@ -40,8 +40,8 @@ if ( count ( $args ) < 2 ) {
die( die(
"Usage: $self [options...] <srcfile.mp4> <destfile.mp4>\n" . "Usage: $self [options...] <srcfile.mp4> <destfile.mp4>\n" .
"Options:\n" . "Options:\n" .
" --letterbox pad instead of cropping\n" . " --crop crop instead of padding\n" .
" --audio include audio\n" . " --no-audio strip audio\n" .
" --exposure=n adjust exposure\n" . " --exposure=n adjust exposure\n" .
" --peak=n set HDR peak nits\n" . " --peak=n set HDR peak nits\n" .
" --fps=n frame rate limit\n" . " --fps=n frame rate limit\n" .
@ -141,16 +141,21 @@ function convert( $src, $dest, $options ) {
$bitrate = floor( $maxBits / $duration ); $bitrate = floor( $maxBits / $duration );
if ( $options[ 'audio' ] ) { if ( $options[ 'no-audio' ] ) {
$audioBitrate = 96 * 1000;
$audio = [ '-b:a', $audioBitrate ];
$bitrate -= $audioBitrate;
} else {
$audio = [ '-an' ]; $audio = [ '-an' ];
} else {
$audioBitrate = 96 * 1000;
$audio = [
'-ac', 2,
'-b:a', $audioBitrate,
];
$bitrate -= $audioBitrate;
} }
$bitrate = max( $bitrate, 16000 );
$mbits = 1000 * 1000; $mbits = 1000 * 1000;
$base = intval( $mbits * $options['quality'] ); $base = intval( $mbits * floatval( $options['quality'] ) );
if ( $bitrate < 1 * $base || $height < 480 ) { if ( $bitrate < 1 * $base || $height < 480 ) {
$frameWidth = 640; $frameWidth = 640;
$frameHeight = 360; $frameHeight = 360;
@ -167,22 +172,22 @@ function convert( $src, $dest, $options ) {
$aspect = $width / $height; $aspect = $width / $height;
$wide = $aspect > ( $frameWidth / $frameHeight ); $wide = $aspect > ( $frameWidth / $frameHeight );
$pad = boolval( $options['letterbox'] ); $crop = boolval( $options['crop'] );
if ( $pad ) { if ( $crop ) {
if ( $wide ) { if ( $wide ) {
$scaleWidth = $frameWidth;
$scaleHeight = evenize( $frameWidth / $aspect );
} else {
$scaleHeight = $frameHeight; $scaleHeight = $frameHeight;
$scaleWidth = evenize( $frameHeight * $aspect ); $scaleWidth = evenize( $frameHeight * $aspect );
} else {
$scaleWidth = $frameWidth;
$scaleHeight = evenize( $frameWidth / $aspect );
} }
} else { } else {
if ( $wide ) { if ( $wide ) {
$scaleHeight = $frameHeight;
$scaleWidth = evenize( $frameHeight * $aspect );
} else {
$scaleWidth = $frameWidth; $scaleWidth = $frameWidth;
$scaleHeight = evenize( $frameWidth / $aspect ); $scaleHeight = evenize( $frameWidth / $aspect );
} else {
$scaleHeight = $frameHeight;
$scaleWidth = evenize( $frameHeight * $aspect );
} }
} }
@ -201,12 +206,12 @@ function convert( $src, $dest, $options ) {
$filters[] = "zscale=t=bt709:m=bt709:r=full"; $filters[] = "zscale=t=bt709:m=bt709:r=full";
} }
$filters[] = "format=yuv420p"; $filters[] = "format=yuv420p";
if ( $options['letterbox'] ) { if ( $crop ) {
$filters[] = "crop=w=$frameWidth:h=$frameHeight";
} else {
$offsetX = round( ( $frameWidth - $scaleWidth) / 2 ); $offsetX = round( ( $frameWidth - $scaleWidth) / 2 );
$offsetY = round( ( $frameHeight - $scaleHeight) / 2 ); $offsetY = round( ( $frameHeight - $scaleHeight) / 2 );
$filters[] = "pad=w=$frameWidth:h=$frameHeight:x=$offsetX:y=$offsetY"; $filters[] = "pad=w=$frameWidth:h=$frameHeight:x=$offsetX:y=$offsetY";
} else {
$filters[] = "crop=w=$frameWidth:h=$frameHeight";
} }
$vf = implode( ',', $filters ); $vf = implode( ',', $filters );