こしあん
2019-06-27

OpenCVで作成した動画がブラウザで正常に表示できない場合の解決法

Pocket
LINEで送る


OpenCVで作成した動画をサイトで表示する場合、ローカルで再生できていても、ブラウザ上では突然プレビューがでなり、ハマることがあります。原因の特定が難しい現象ですが、動画を作成する際にH.264形式でエンコードするとうまくいきました。その方法を解説します。

MPV4は手軽だが…

OpenCVで動画を作成する例で検索すると、おそらくこっちのほうが多く出てくると思うのですが、fourccにMP4Vを指定するパターンです。

directory以下のPNGファイルを1つのMP4ファイルにまとめてみましょう。

import cv2
import glob

# よくある例
def create_mp4(directory):
    # コーデックの指定
    fourcc = cv2.VideoWriter_fourcc("m", "p", "4", "v")
    # 引数はファイル名、コーデック、FPS、解像度(横、縦)
    video = cv2.VideoWriter(directory+".mp4", fourcc, 5.0, (640, 480))

    files = sorted(glob.glob(directory + "/*.png"))
    for f in files:
        img = cv2.imread(f)
        video.write(img)

これはローカルPCではうまく行きます。そしてメディアプレーヤーで再生してもちゃんと表示されます。しかし、作成した動画をブラウザで表示しようとすると急に沼にハマります

WordPressだとエラー

「Media error: Format(s) not supported or source(s) not found」というエラーが出てしまいます。

このエラーで検索すると、いくつかそれっぽい理由が出てきました。

  • ファイルサイズが上限にかかっていて正常にアップロードできない(php.iniに問題あるケース)
  • WordPressのバグだという主張

一点目は自分のサーバーだと128MBまでアップロードでき、ファイルサイズは10MB程度だったので引っかかることはありませんでした。サーバーのファイルマネージャーから当該のアップロード済ファイルをダウンロードして、ローカルPCのメディアプレーヤーで開くと正常に表示できました。したがって、アップロード自体に失敗しているということは考えられません。アップロード自体は成功しています。

二点目は例えばこちらのフォーラムにありますが、WordPressのバグだという説が浮上しています。しかし、明確な解決法は特に示されていませんでした。

一方で、MP4のURLを直打ちするとChromeでのプレビューは以下のようになりました。

プレビューができていない??

つまり、正常にアップロードできているのに再生ができないということになります。

ローカルファイルをChromeやFirefoxで開いてもエラー

なら作成したMP4のローカルファイルをChromeで開くとどうかというと、上の図と同じ状態になりました。

ブラウザを変えてみるとどうかというと、Firefoxでは次のようになりました。

Chromeと同様に再生できません。つまり、作成した動画ファイル自体に問題があるということになります。

原因はコーデック

諸悪の根源はコーデックでした。こちらのStackOverFlowの記事が参考になりました。

この記事によると、「MP4Vはほとんどのブラウザでサポートされていないから、代わりにH264を使いなさい」とのこと。H264への切り替えは簡単で、fourccの設定を、

fourcc = cv2.VideoWriter_fourcc("H", "2", "6", "4")

とするだけ。じゃあそのままこれで実行すれば終わりかというともう一歩あります。

OpenH264が必要

H.264でエンコードするにはOpenH264というライブラリが別途必要になります。主にライセンスの関係です。試しにOpenH264なしでエンコードしようとすると、

Failed to load OpenH264 library: openh264-1.8.0-win64.dll
        Please check environment and/or download library: https://github.com/cisco/openh264/releases

「OpenH264を取ってこい」と怒られてしまいます。

本来H.264を使うにはMPEG-LAにライセンス料を支払う必要があります。しかし、OepnH264という、Ciscoがオープンソースとして公開しているビルドされたライブラリを使う限りにおいては、このライセンス料をCiscoが肩代わりしてくれるという契約があるのです。OpenCVでOpenH264を必要としているのもこれが理由です。

また、過去のニュース:2011年を読んでいるとChromeがH.264のサポートを切る予定との報道もありましたが、現在はこのOpenH264を通じてChromeもFirefoxもH.264の再生は可能になっています。

しかし、これはあくまでビルド済みのバイナリを使う上では使用料いらないよということであって、オープンソースのコードを自分でビルドする場合はこの契約から外れるそうです(つまりライセンス料払う必要がある)。詳しくはこちら

早い話がOpenH264のリリースビルドを取ってくれば良いということなのでサクッとダウンロードします。

  1. https://github.com/cisco/openh264/releasesこのページにアクセス
  2. ただし、バージョンは正確に一致する必要がある。1.8.0を要求していて(この例)、2.0.0をダウンロードすると「バージョンが違うぞ」って怒られる。
  3. Windowsの場合は、OpenCVのバージョンにもよるが「openh264-1.8.0-win64.dll.bz2」をダウンロードすればOK
  4. ダウンロードしたアーカイブを解凍(WinRARでできる)
  5. dllファイルをPythonのカレントディレクトリにコピー

dllのコピーを忘れないようにしましょう。コードを実行するとH.264のMP4が出来上がります。

試しにローカルのMP4ファイルをFirefoxやChromeで開くと無事表示することができました。

アップロードし、WordPressでもちゃんとプレビューできるようになりました。やったぜ。

まとめ

OpenCVで保存した動画をブラウザ上で表示(サイト表示を含む)したいときは、H.264形式で保存するとよい。その際OpenH264が必要になるので、必要なバージョンを正確にダウンロードしましょう。

以上です。

Related Posts

keras_preprocessingを使ってお手軽に画像を回転させる方法... Data Augmentationで画像を回転させたいことがあります。画像の回転は一般に「アフィン変換」と呼ばれる操作で、OpenCVやPillowのライブラリを使えば簡単にできるのですが、Numpy配列に対して1から書くとかなりめんどいのです。Kerasが裏で使っているkeras_preproc...
Python(Numpy)で画像を水平反転する方法:Data Augmentation向け... OpenCVを使わずに単純に画像を左右反転(水平反転)する方法を考えます。ディープラーニングでデータのジェネレーターを自分で実装した場合、Data Augmentationを組み込む際にも必要になります。それを見ていきましょう。 左右反転自体は実は簡単 例えばNumpyの行列を左右反転させてみ...
KerasのCallbackを使って継承したImageDataGeneratorに値が渡せるか確かめ... Kerasで前処理の内容をエポックごとに変えたいというケースがたまにあります。これを実装するとなると、CallbackからGeneratorに値を渡すというコードになりますが、これが本当にできるかどうか確かめてみました。 想定する状況 例えば、前処理で正則化に関係するData Augmenta...
クラス別のData Augmentationって意味ある?を調べてみた... Data Augmentationで精度を上げることにお熱になっていると、「特定の足引っ張っているクラスだけAugmetationかけたらいいんじゃない?」的なことをやりたくなります。これを調べてみました。その結果、全体を一括で処理するケースと、クラス別に局所的な処理をするケースで、精度に大きなギ...
TPUでアップサンプリングする際にエラーを出さない方法... 画像処理をしているとUpsamplingが必要になることがあります。Keras/TensorFlowではUpsampling2Dというレイヤーを使ってアップサンプリングができますが、このレイヤーがTPUだとエラーを出すので解決法を探しました。自分でアップサンプリングレイヤーを定義するとうまく行った...
Pocket
LINEで送る
Delicious にシェア

Add a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です