TIPs of C# – #001. 動画の保存

前提条件

OS:Windows 11 Pro
Visual Studio:v17.6.4
OpenCVSharp4: 4.7.0.20230115

動画を保存したい

たまにプログラム的に描画した画像列を動画として保存したい時があります。(自分だけ?)

昔は、Video For Windowsなどのライブラリを利用して動画に保存したりできてたと記憶していますが、最近は正式なVideo For Windowは.NETにはなさそうです。

保存するためのライブラリ

ネットで調べると、Nugetからインストールできる動画保存に利用できそうなライブラリは下記がありそうです。

ライブラリ入力する画像データ形式
AForge.VideoBitmap
OpenCVSharp4(ffmpeg)Mat

個人的にOpenCVSharpは良く使うので、OpenCVSharp4を利用したいと思います。

懸念点

OpenCVで利用されているffmpegは内部のコードにH264やX264などの特許に関係するものが含まれているので、ビジネスとして利用する場合(動画保存機能を搭載したアプリの配布など?)、ライセンス料が発生する事があると聞いた事があります。

※配布されているライブラリのライセンスが無償でも内部のコードが特許に引っかかる場合があるので、3rdパーティライブラリを利用する場合は、注意が必要です。

今回は個人向けの動画を作るだけなので、その点はそれほど気にしなくてよいでしょう…。

動画保存テスト

※OpenCVSharp4のNugetでのインストールは割愛します…。

テストコード①

ネットには、WEBカメラの画像をキャプチャして動画として保存する例が紹介されていますが、今回は動画保存だけがメインなので、下記の様なコードをプログラムに組み込みます。

try
{
    // 各フレームに書き込む画像の準備
    Mat img = new Mat(720, 1280, MatType.CV_8UC3);
    // 保存先の設定(拡張子をmp4, 動画形式をH264、フレームレートを30fps, サイズは画像サイズ)
    VideoWriter vw = new VideoWriter("C:\TMP\test.mp4", FourCC.H264, 30, img.Size());
    // フレームの保存(90 frames / 30 fps => 3 sec)
    for (int i = 0; i < 90; i++)
    {
        // フレームの書き込む
        vw.Write(img);
    }
    // VideoWriterのリリース
    vw.Release();
    // VideoWriterのDispose
    vw.Dispose();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

さてこのコードを埋め込んだプログラムを実行させると、エラーもなく終了しますが、動画ファイルはどこにもありません…(保存できていません)

ネットを見ていると、『H264のDLLを実行ファイルと同じ場所に置かないとだめだ』という情報がありましたので、それも試しましたが結果は同じでした。(そもそも、その情報がPython向けOpenCVの情報という噂もありますが…)

テストコード②

どこかでエラーが出ているはずという事でIsOpened()でVideoWriterが正常に生成されているかを確認するコードを付けました。

try
{
    // 各フレームに書き込む画像の準備
    Mat img = new Mat(720, 1280, MatType.CV_8UC3);
    // 保存先の設定(拡張子をmp4, 動画形式をH264、フレームレートを30fps, サイズは画像サイズ)
    VideoWriter vw = new VideoWriter("C:\TMP\test.mp4", FourCC.H264, 30, img.Size());
    // 保存先がオープンされているかどうかで処理を分ける
    if (vw.IsOpened() == true)
    {
        // フレームの保存(90 frames / 30 fps => 3 sec)
        for (int i = 0; i < 90; i++)
        {
            // フレームの書き込む
            vw.Write(img);
        }
        // VideoWriterのリリース
        vw.Release();
    }
    else
    {
        // オープンされていない…
        MessageBox.Show("Video Writer is NOT opened");
    }
    // VideoWriterのDispose
    vw.Dispose();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

結果は『Video Writer is NOT opened』のメッセージボックスが表示され、やはりVideoWriterがきちんと生成できていない様です。

詰んだ?

コードもエラーもなく、動作時に例外も出ない…詰んだかなと思いました。

ただ、ネットを調べていると、動画の拡張子を「avi」にしている例や、FourCCのタイプを「DIVX」にしている例があり、もしかして、ファイル拡張子と動画形式の組み合わせでうまく行ったり、行かなかったりする場合があるかもと思い至りました。

組み合わせをチェック

拡張子は下記の4つ、

“.avi”, “.wmv”, “.mpg”, “.mp4”

FourCCは下記43個、

FourCC.Default, FourCC.AVC, FourCC.CVID, FourCC.DIB, FourCC.DIV3,
FourCC.DIVX, FourCC.DV25, FourCC.DV50, FourCC.DVC, FourCC.DVHD,
FourCC.DVSD, FourCC.DVSL, FourCC.H261, FourCC.H263, FourCC.H264,
FourCC.H265, FourCC.HEVC, FourCC.I420, FourCC.IV32, FourCC.IV41,
FourCC.IV50, FourCC.IYUB, FourCC.IYUV, FourCC.JPEG, FourCC.MJPG,
FourCC.M4S2, FourCC.MP42, FourCC.MP43, FourCC.MP4S, FourCC.MP4V,
FourCC.MPG1, FourCC.MPG2, FourCC.MPG4, FourCC.MSS1, FourCC.MSS2,
FourCC.MSVC, FourCC.PIM1, FourCC.WMV1, FourCC.WMV2, FourCC.WMV3,
FourCC.WVC1, FourCC.X264, FourCC.XVID

これらの組み合わせ172組の中でIsOpened()がtrueを返し、正常に動画が保存できるものを探しました。

動画が保存できる組み合わせ

結果としては、下記の組み合わせでうまく行きました。

拡張子動画形式
.aviFourCC.MJPG(モーションJPEG)

172組も組み合わせがあるのに、サポートされるのは「モーションJPEG形式のAVI」のみか…。
(もう少し、他の組み合わせもできると思っていましたが…)

もしかしたら、OpenCVSharpライブラリの配布にあたって、特許に抵触しない様にコードが無効化されているのかも知れません(実際はわかりませんが…)。

補足情報

動画データとして保存できるようになりましたが、以下補足情報です。

アニメーションにするには

動画をアニメーションさせるには、Write()メソッドに渡すMat形式の画像をフレーム位置に応じた画像データを渡すだけです。

WEBカメラから取得した画像データをWrite()に逐次渡せば、カメラ画像の動画データになりますね。

動画の品質

デフォルトのままでは動画の品質は必ずしも良いものではないので、下記のコードを加えておきます。

// 品質を設定(1:低~100:高)
vw.Set(VideoWriterProperties.Quality, 100);

品質を上げればファイルサイズは増加しますが、最近のPCのストレージのサイズを考えれば最高品質にしておいて問題ないでしょう。

AVIファイルは使い勝手が悪い

MJPG形式のAVIファイルはWindowsPC上ではメディアプレーヤーなどで再生はできますが、WordPressなどに動画を貼り付けても正しい動作として認識してくれません。

汎用的な動画にするには動画編集ソフトなどを使って、AVI→MP4(H264など)へ変換する必要があります。

※それであれば、PNGなどで画像列として保存して、動画編集ソフトで動画にした方が劣化がなくて良いかも知れません…。フレーム数が多いと大変ですが…。


投稿一覧はこちら