diff --git a/pack-set b/pack-set index 40dbe44..7357af7 100755 --- a/pack-set +++ b/pack-set @@ -8,7 +8,7 @@ do SPEED_SMALL="veryslow" SPEED_LARGE="medium" - SMALL="$COMMON --size=4m --preset=$SPEED_SMALL --quality=0.75" + SMALL="$COMMON --size=4m --preset=$SPEED_SMALL" LARGE="$COMMON --size=25m --preset=$SPEED_LARGE" pack-vid $SMALL "$INFILE" "${INFILE%.mp4}-small.mp4" diff --git a/pack-vid b/pack-vid index e18e7e4..207dbe9 100755 --- a/pack-vid +++ b/pack-vid @@ -26,6 +26,7 @@ $options = [ 'fps' => '60000/1001', 'size' => $maxBytes, 'quality' => 1.0, + 'hdr' => false, ]; while ( count( $args ) > 0 && substr( $args[0], 0, 2 ) == '--' ) { @@ -51,7 +52,8 @@ if ( count ( $args ) < 2 ) { " --preset=key set h.264 encoding preset\n" . " --fps=n frame rate limit\n" . " --size=n target file size in bytes (default 3.5M)\n" . - " --quality=n fraction of base bitrate to break on (deafult 0.75)\n" + " --quality=n fraction of base bitrate to break on (deafult 0.75)\n" . + " --hdr force HDR input processing on\n" ); } [ $src, $dest ] = $args; @@ -97,7 +99,7 @@ function ffprobe( $path ) { } function evenize( $n ) { - $n = ceil( $n ); + $n = round( $n ); if ( $n & 1 ) { $n++; } @@ -140,7 +142,7 @@ function convert( $src, $dest, $options ) { $duration = floatval( $track->duration ); $width = $track->width; $height = $track->height; - $hdr = $track->color_primaries === 'bt2020'; + $hdr = $track->color_primaries === 'bt2020' || $options['hdr']; $keyframeInt = ceil( $duration * 60 ); $bitrate = floor( $maxBits / $duration ); @@ -161,6 +163,7 @@ function convert( $src, $dest, $options ) { $mbits = 1000 * 1000; $base = intval( $mbits * floatval( $options['quality'] ) ); + /* if ( $bitrate < 1 * $base || $height < 480 ) { $frameWidth = 640; $frameHeight = 360; @@ -182,8 +185,49 @@ function convert( $src, $dest, $options ) { $frameHeight = 1080; $bitrate = min( $bitrate, $base * 8 ); } + */ $aspect = $width / $height; + $pixels = $width * $height; + + // canonical base rate is 1 megabit at 480p + $bitrate = min( $bitrate, 4 * $base ); + + $minWidth = 640; + $minHeight = 360; + + $baseWidth = 854; + $baseHeight = 480; + $pixelsPerBit = ( $baseWidth * $baseHeight ) / $base; + + $maxWidth = 1920; + $maxHeight = 1080; + $maxrate = $base * ( $maxWidth * $maxHeight ) / ( $baseWidth * $baseHeight ); + + $pixels = $bitrate * $pixelsPerBit; + $frameHeight = evenize( sqrt( $pixels / $aspect ) ); + $frameWidth = evenize( $frameHeight * $aspect ); + + if ( $aspect > 16 / 9 ) { + if ( $frameWidth < $minWidth ) { + $frameWidth = $minWidth; + $frameHeight = evenize( $frameWidth / $aspect ); + } elseif ( $frameWidth > $maxWidth ) { + $frameWidth = $maxWidth; + $frameHeight = evenize( $frameWidth / $aspect ); + $bitrate = min( $bitrate, $maxrate ); + } + } else { + if ( $frameHeight < $minHeight ) { + $frameHeight = $minHeight; + $frameWidth = evenize( $frameHeight * $aspect ); + } elseif ( $frameWidth > $maxWidth ) { + $frameHeight = $maxHeight; + $frameWidth = evenize( $frameHeight * $aspect ); + $bitrate = min( $bitrate, $maxrate ); + } + } + $wide = $aspect > ( $frameWidth / $frameHeight ); $crop = boolval( $options['crop'] ); $letterbox = boolval( $options['letterbox'] );