Created
October 13, 2021 02:16
-
-
Save brlodi/67e151c81e20f4fc4c0a55757897d87c to your computer and use it in GitHub Desktop.
When Blue Iris writes exported clips that switch between the substream and main stream, they're just streams of frames with varying resolutions. Most video players don't like that, because they expect all frames of a video to be the same size. This intelligently reencodes such videos *only if needed* so they can be consumed by other software.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function bi_fix_multires | |
function _get_frames_info -a f field_name | |
ffprobe -hide_banner -skip_frame nokey -show_frames -show_entries frame=$field_name $f 2>/dev/null | awk -F'=' "/$field_name/{print \$2}" | |
end | |
function _get_stream_info -a f field_name | |
ffprobe -hide_banner -show_entries stream=$field_name $f 2>/dev/null | awk -F'=' "/$field_name/{print \$2}" | |
end | |
set --local files (du $argv | sort -n | awk '{print $2}') | |
for f in $files | |
echo -n "Checking $f..." | |
set --local of (string split -r -f 1 -m 1 . $f).fixed.(string split -r -f 2 -m 1 . $f) | |
# Extracting this data is very slow, but still orders of magnitude faster | |
# than unnecessarily transcoding a large video | |
set --local codec (_get_stream_info $f codec_name) | |
set --local codec_tag (_get_stream_info $f codec_tag_string) | |
set --local frame_rate (_get_stream_info $f r_frame_rate) | |
set --local frame_heights (_get_frames_info $f height | sort -unr) | |
set --local frame_widths (_get_frames_info $f width | sort -unr) | |
set --local target_height $frame_heights[1] # maximum detected frame height | |
set --local target_width (math "ceil($target_height * 16 / 9)") | |
# echo "\n detected widths: ["(string join ", " $frame_widths)"], detected heights: ["(string join ", " $frame_heights)"], target resolution = "$target_width"x"$target_height | |
# If there's only a single frame height in the file we check that it's | |
# actually a 16x9 image. If both are true, we skip reencoding the video. | |
if test \( (count $frame_heights) -eq 1 \) -a \( $target_width -eq $frame_widths[1] \) | |
# We don't need to reencode, but while we're here we can swap the HEVC tag | |
# to the one macOS and iOS can natively recognize. This is just metadata | |
# so it's essentially free to fix performance-wise. | |
if test \( $codec = "hevc" \) -a \( $codec_tag != "hvc1" \) | |
echo -n " fixing HEVC tags..." | |
ffmpeg -hide_banner -loglevel error -hwaccel auto -i "$f" -c:v copy -c:a copy -tag:v hvc1 $of | |
echo -e " done!\n" | |
else | |
echo -e " nothing to fix!\n" | |
end | |
else | |
# Otherwise, reencode the file to be the proper & consistent size and | |
# aspect ratio so standard programs can read it easily | |
echo " re-rendering to $of" | |
ffmpeg -hide_banner -loglevel error -stats -hwaccel auto -i "$f" -vf "scale=$target_width:$target_height" -c:a copy -c:v libx265 -x265-params log-level=none -crf 24 -tag:v hvc1 $of | |
end | |
end | |
# Clean up "private" functions | |
functions -e _get_frames_info | |
functions -e _get_stream_info | |
end | |
bi_fix_multires ./test/*.mp4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment