summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKen D'Ambrosio <ken@jots.org>2026-06-18 22:33:09 +0000
committerKen D'Ambrosio <ken@jots.org>2026-06-18 22:33:09 +0000
commitfaec9c5448dfe3bbb7e187c7fb4d58557b70035d (patch)
treeecd3d91946cc61372a76687a0a3735a59fcb3693
parentc5ec42b2f42e285a95610f1b9b9efba4beef3d7e (diff)
Detect and fix non-4:2:0 chroma in H.264 MP4s during transcode
Browsers only decode H.264 4:2:0 (Baseline/Main/High). Files reported as codec_name=h264 could still be High 4:2:2/4:4:4 profile if an earlier transcode pass (or the source) used non-standard chroma — ffprobe/ffmpeg read these fine, but real browsers reject them as unsupported. update.rb now also checks pix_fmt and re-transcodes if it isn't yuv420p/yuvj420p, and forces -pix_fmt yuv420p on output so this can't recur. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--scripts/update.rb17
1 files changed, 15 insertions, 2 deletions
diff --git a/scripts/update.rb b/scripts/update.rb
index 996ecbd..37cdf29 100644
--- a/scripts/update.rb
+++ b/scripts/update.rb
@@ -37,6 +37,7 @@ AUDIO_EXTS = %w[mp3 flac ogg wav m4a aac].freeze
MEDIA_EXTS = (IMAGE_EXTS + VIDEO_EXTS + AUDIO_EXTS).freeze
TRANSCODE_EXTS = %w[avi mkv mov].freeze
WEB_VIDEO_CODECS = %w[h264 vp8 vp9 av1].freeze
+WEB_PIX_FMTS = %w[yuv420p yuvj420p].freeze
SENTINEL_FILE = '.albumen_scanned'.freeze
# Explicit directory argument implies force — you asked for it, it should run.
@@ -102,7 +103,8 @@ def process_dir(dir, idx, total)
true
elsif ext == 'mp4' || ext == 'm4v'
codec = video_codec(full)
- codec && !WEB_VIDEO_CODECS.include?(codec)
+ pix = video_pix_fmt(full)
+ codec && (!WEB_VIDEO_CODECS.include?(codec) || !WEB_PIX_FMTS.include?(pix))
else
false
end
@@ -251,10 +253,21 @@ rescue StandardError
nil
end
+def video_pix_fmt(path)
+ out = IO.popen(
+ ['ffprobe', '-v', 'quiet', '-select_streams', 'v:0',
+ '-show_entries', 'stream=pix_fmt', '-of', 'default=noprint_wrappers=1:nokey=1', path],
+ err: '/dev/null', &:read
+ ).strip
+ out.empty? ? nil : out
+rescue StandardError
+ nil
+end
+
def transcode_to_mp4(source, dest)
system(
'ffmpeg', '-y', '-i', source,
- '-c:v', 'libx264', '-crf', '23', '-preset', 'medium',
+ '-c:v', 'libx264', '-crf', '23', '-preset', 'medium', '-pix_fmt', 'yuv420p',
'-c:a', 'aac',
'-movflags', '+faststart',
dest,