iOS Safari と非互換な VP9 動画アップロードを自動検出または拒否

最近、自己ホスト型の Discourse フォーラムにあるいくつかの動画が、iPhone や iPad で再生されずに静かに失敗していることに気づきました。調査の結果、根本的な原因は、動画が VP9 コーデックでエンコードされ、MP4 コンテナに格納されていたことです。この組み合わせは iOS Safari では再生できません。

発生メカニズム

Facebook(および他のプラットフォームも同様)では、ユーザーがコンテンツをダウンロードする際に、VP9 エンコードされた動画が提供されることがあります。これらのファイルを Discourse にアップロードすると、拡張子が .mp4 であるため、内部のコーデックが何であるかを示す手がかりがなく、問題なく受け入れられます。デスクトップブラウザや Android では動画が正常に再生されるため、この問題は見過ごされがちです。一方、iOS Safari では動画にサムネイルと再生ボタンが表示されますが、タップしても回転するインジケーターが表示されるだけです。ユーザーは通常、これがネットワークの問題だと誤解し、報告せずに次の行動に移ってしまいます。

検出が難しい理由

  • ファイル拡張子(.mp4)は、正常に動作する H.264 ファイルと同一である
  • デスクトップブラウザは VP9 をサポートしているため、管理者がデスクトップでテストしても問題に気づかない
  • iOS ユーザーは、同じ投稿内の他のコンテンツが表示され再生可能である場合、個別のメディア再生失敗を報告しないことが多い
  • 管理者向けの警告やエラーメッセージが存在しない

推奨される解決策

動画のアップロード時に、Discourse が動画コーデックを検査(Docker コンテナ内には既に ffprobe が用意されています)し、以下のいずれかの対応を取ることが考えられます。

  1. アップロードを拒否し、「VP9 は iOS でサポートされていないため、H.264 に再エンコードしてください」という明確なメッセージを表示する
  2. アップロード時に動画を自動的に H.264 にトランスコードする(一部のプラットフォームがアップロードを正規化する手法に類似)

オプション 1 は実装が比較的簡単で、すでに大きな改善となります。オプション 2 は、シームレスなユーザー体験を実現するために理想的です。

環境

  • Docker 上で自己ホスト型の Discourse(ローカルストレージ、S3 未使用)
  • Discourse バージョン:2026.4.0-latest
  • Discourse の nginx の前面に Apache リバースプロキシを配置

回避策

この問題に遭遇した管理者の場合、以下の手順で対応が必要です。

  1. ffprobe を使用して VP9 ファイルを特定する
  2. ffmpeg -c:v libx264 -profile:v main -level 3.1 -r 30 -movflags +faststart で H.264 に再エンコードする
  3. uploads テーブル内の sha1urlfilesize を更新する
  4. 影響を受けた投稿の生 Markdown 内の upload:// ショート URL トークンを更新する
  5. 影響を受けた投稿を再構築(rebake)する

これは、ほとんどのフォーラム管理者が実施できるようなものではない、複雑な手動プロセスです。

「いいね!」 1

自動トランスコードについては、Discourse Video Stream :movie_camera:をご確認ください。

ローカルでの自動トランスコードは機能しますが、それをほとんどの環境で安全に配信できる方法が主な課題です。

「いいね!」 2

@Falco さん、Video Stream プラグインのヒントをありがとうございます。私のような小規模な愛好家フォーラムにとっては、有料のサードパーティ製サービスへの依存を追加するのは、問題の規模に比べて過剰に感じられます。ただし、動画利用の多い高トラフィックサイトにとっては魅力的な選択肢であることは理解できます。

ローカルでのトランスコードに関するご指摘は興味深いです。修正プロセス中に、VPS で 9 件の対象ファイルに対して手動で ffmpeg を実行しましたが、サーバーは問題なく処理できました。アップロード時に同期で実行することへの懸念は理解しています。CPU の急上昇、タイムアウト、ディスクへの負荷はすべて現実的なリスクです。しかし、非同期のバックグラウンドジョブアプローチでこれらの懸念の多くは解消されないでしょうか?アップロードは通常通り完了し、トランスコードはその後キューイングされたジョブとして実行されるという仕組みです。これは Discourse がすでに画像のサムネイル生成で採用している方法と類似しています。動画はジョブが完了するまで iOS で再生できなくなりますがおそらく許容できるトレードオフだと思われます。

完全なトランスコードに至らなくても、より軽量なオプションとして、アップロード時に VP9 を検知し、明確なエラーメッセージで拒否するか、管理パネルでフラグを立てるだけでも、技術的な背景が乏しい自己ホスト管理者にとって、iOS での再生失敗を黙って見過ごす問題を大幅に軽減できるはずです。

「いいね!」 1

動画はもう少し複雑です。ユーザーが悪意を持ってCPUを占有するようなファイルをアップロードする可能性が非常に多く、特に多くの1vCPUの自己ホストインスタンスではそのリスクが高まります。

ここではプラグインとして実装することを検討します。そうすれば、トレードオフを理解した上で希望する管理者のみがそのオプションを利用できるようになります。

「いいね!」 3