動画アップロード機能を実装していると、「MOVをMP4に変えれば再生できる」「拡張子がMP4ならH.264だろう」と考えたくなります。しかし、拡張子はコンテナを示すだけで、内部の映像・音声コーデックまでは保証しません。
たとえばMOVにはH.264、HEVC、ProResなどが入り得ます。MP4にもH.264以外の映像が入るため、拡張子やブラウザの File.type だけで処理方法を決めると、変換後も再生できない、不要な再エンコードで画質が落ちる、といった問題が起きます。
この記事では、アップロードされた動画を調べ、リマックス(remux)で済むのか、再エンコードが必要なのかを判断する手順を整理します。
1. コンテナとコーデックを分けて考える
- コンテナ:映像、音声、字幕、メタデータをまとめる入れ物。MP4、MOV、WebM、MKVなど
- 映像コーデック:映像の圧縮方式。H.264、HEVC、VP9、AV1、ProResなど
- 音声コーデック:AAC、Opus、MP3、PCMなど
「MOVからMP4へ」はコンテナ変更の話ですが、内部のコーデックが出力先で扱えなければ、コンテナを替えるだけでは解決しません。
2. まず ffprobe で実体を確認する
拡張子ではなく、実ファイルを調べます。
ffprobe -v error \
-show_entries format=format_name,duration,size \
-show_entries stream=index,codec_type,codec_name,profile,width,height,avg_frame_rate \
-of json input.mov
確認したいポイントは次の通りです。
| 項目 | 判断に使う内容 |
|---|---|
format_name |
実際のコンテナ形式 |
codec_type |
video / audio / subtitle の区別 |
codec_name |
h264、hevc、prores、aac など |
width / height
|
解像度と処理負荷の見積もり |
duration / size
|
時間・容量制限の検証 |
avg_frame_rate |
フレームレートの確認 |
ファイル名やMIMEタイプは入力時のヒントにはなりますが、最終判断の根拠にはしません。
3. リマックスで済むケース
映像・音声コーデックが目的の再生環境に対応していて、コンテナだけをMP4に替えたい場合は -c copy が使えます。
ffmpeg -i input.mov \
-map 0:v:0 -map '0:a:0?' \
-c copy -movflags +faststart output.mp4
この方法は映像と音声を再圧縮しないため、一般に高速で、再エンコードによる画質劣化もありません。+faststart はMP4のメタデータを先頭側へ移し、Web配信時に再生を開始しやすくします。
ただし、入力がProRes映像やPCM音声などで、対象プレーヤーがその組み合わせを扱えない場合は、MP4へ詰め替えただけでは目的を満たしません。
4. 再エンコードが必要なケース
次の場合は再エンコードを検討します。
- 対象ブラウザや端末が入力コーデックに対応していない
- ファイル容量を小さくしたい
- 解像度、ビットレート、フレームレートを変更したい
- 編集フィルターを適用したい
互換性を重視してH.264/AACのMP4を作る例です。
ffmpeg -i input.mkv \
-map 0:v:0 -map '0:a:0?' \
-c:v libx264 -crf 23 -preset medium \
-c:a aac -b:a 128k \
-movflags +faststart output.mp4
crf は小さいほど高画質・大容量になります。固定値を万能設定として扱わず、入力解像度、動きの量、用途、許容処理時間で調整します。
5. ブラウザ側の検証は「早期フィードバック」に限定する
ブラウザでは、選択直後に明らかな入力違反を知らせると使いやすくなります。
const file = input.files?.[0];
if (!file) throw new Error("ファイルが選択されていません");
const MAX_BYTES = 500 * 1024 * 1024;
if (file.size > MAX_BYTES) {
throw new Error("ファイルサイズの上限を超えています");
}
// File.type は空の場合や、実体と一致しない場合があるため参考情報に留める
const mimeHint = file.type || "application/octet-stream";
console.log({ name: file.name, size: file.size, mimeHint });
ただし、クライアント側の値は改変できます。サーバー側では少なくとも次を再確認します。
- マジックバイトと解析結果が許可形式か
- 実際の動画・音声ストリームが存在するか
- 容量、再生時間、解像度が上限内か
- 解析不能・破損ファイルを安全に拒否できるか
- 処理ジョブの参照・ダウンロードが作成者本人に限定されているか
- 言語別URLをまたいでも利用回数が合算されるか
特に多言語対応したサービスでは、/ja などの入口ごとに別カウントすると、ルートを変えるだけで限額を回避できてしまいます。限流キーは画面言語ではなく、認証ユーザー、匿名セッション、IPなどのポリシー単位で集約する必要があります。
6. 実装時の判断フロー
実務では次の順序にすると整理しやすくなります。
- 実ファイルを解析する
- 出力先で必要なコンテナと対応コーデックを定義する
- ストリームコピー可能ならリマックスする
- 互換性・圧縮・編集が必要な場合だけ再エンコードする
- 出力を再度
ffprobeで検証する - 対象ブラウザ・端末で再生テストする
ローカルにFFmpeg環境を用意できない利用者向けには、VideoCompress.ioの日本語版で用途別のオンラインツールを案内しています。形式やコーデックを変える必要がある場合はオンライン動画変換、MOVをMP4として扱いやすくしたい場合はMOVからMP4への変換を利用できます。オンライン処理ではアップロード条件、ファイル制限、プライバシー説明を確認してから使うのが安全です。
筆者はVideoCompress.ioの運営に関わっています。上記リンクは実装方法の代替手段として関連箇所に限定して掲載しています。
まとめ
重要なのは「拡張子を変換する」ことではなく、入力ストリームと出力要件の差分を確認することです。先に ffprobe で実体を把握すれば、不要な再エンコードを避けられ、互換性、処理時間、画質、コストの判断もしやすくなります。