日立国際電気「ISnex Viewer」が手に入らないときに.hvs形式の動画を再生・編集したい話―徒労の供養と、AIを使ったアップコンバート&フレーム補完フリーソフトのメモ―

ほとんどの人は、タイトルを見てもなんのことやらさっぱりだと思いますが、検索でこの記事にたどり着いた方、あなたの求めるものはきっとここにあります。

はじめに

日立国際電機の監視カメラシステムISnexシリーズは、録画ファイルが.hvsという見慣れない形式で保存されます。

www.hitachi-kokusai.co.jp

これを再生するには、「ISnex Viewer」というビューワーソフトが必要だそうですが、インストーラーのWeb配信がなく、機器に付属のCDからインストールする必要があります。

.hvsファイルを扱いたいけどCDが手元にない、そんな超ニッチなシュチュエーションを切り抜けるワザをここに記します。

元も子もない話

この記事を8割がた書いたところで、全てを無に帰す気付きがありました。

どうやら相手は、コマごとのJpeg画像を1ファイルにまとめたもののようです。(本文より)

ん? それはMotion JPEGのことでは? .hvsを.mjpegに変更...っと→VLC Playerで普通に再生できた→もちろんmp4などに変換もできた。

まとめ

  • ISnexの.hsv動画は、拡張子を.mjpegに変えると再生できる。
  • さらに、FFmpegを使えば拡張子をいじる必要もなく、そのまま変換できることがわかった。
    • 例:ffmpeg -i 動画.hvs 動画mp4

というわけで、ここから先はただの徒労の記録です。

ただ、それだけでは悲しいので、AIによるアップコンバートとフレーム補完ができるフリーソフトについても簡単に紹介します。

それでは、まず僕の半日分の作業を供養させてください。

そもそも.hvsファイルの正体とは?

検索してみると、YAMAHAの音声合成ソフトが出ますが、もちろん別物です。

ネットでは有力情報が掴めなかったので、バイナリエディタの出番です。

forest.watch.impress.co.jp

とりあえず、Bitmap表示してみると、いかにもフレームの切れ目っぽい線が出ています。

f:id:at_you_key:20220331210649p:plain

線の辺りを見てみると、さっそく怪しげな痕跡が見つかりました、これはもう尻尾を掴んだぞ!

f:id:at_you_key:20220331210731j:plain

この文字列を信じるならば、どうやら相手は、コマごとのJpeg画像を1ファイルにまとめたもののようです。ということは、1コマづつ抜き出して、JPEGファイルとして保存すれば、中身を見ることができそうですね。

JPEGのバイナリ構成

1フレームがどこからどこまでなのか知るには、JPEGファイルの先頭と終端の目印を探す必要があります。

qiita.com

この記事によると、JPEGファイルは先頭がFFD8で始まり、末尾がFFD9で終わることなので、これを参考に先頭から1枚分切り出してみます。

FFD8から

f:id:at_you_key:20220331210759j:plain

DDF9まで

f:id:at_you_key:20220331210816j:plain

末尾は、ビットマップビューを参考にして、線が入っているあたりを見れば簡単に見つかります。

.jpgを付けて保存すると、無事に1コマ分の画像を取り出すことができました!

自動で全フレーム切り出す

こういう単純作業をさくっと自動化したいときは、Pythonの出番です。

import os

# 入力ファイルの情報
target_path = r"c:\tmp"
video_name = "hvsのファイル名"

# 出力先フォルダを用意
output_path = fr"{target_path}\{video_name}"
os.makedirs(output_path, exist_ok = True)

# バイナリ読み込みモードで開く
with open(fr"{target_path}\{video_name}.hvs","rb") as f:
    f_in = f.read()

    # ファイル名連番用のインデックス
    i = 0

    # ファイルを1バイトづつ読み取る
    for idx in range(len(f_in)):

        # ffd8を見つけたら、JPEGファイルを作って開く
        if(f_in[idx] == 0xff and f_in[idx+1] == 0xd8):

            # ファイル名には5桁の連番を付ける
            file_name=fr"{video_name}-{str(i).zfill(5)}.jpg"
            f_out = open(fr"{output_path}\{file_name}","wb")
            print(fr"{output_path}\{file_name}")

        # ひたすらバイト列を転記する
        try:
            f_out.write(bytes([f_in[idx]]))
        except:
            pass

        # ffd9を見つけたらJPEGファイルを閉じる
        if(f_in[idx] == 0xff and f_in[idx+1] == 0xd9):
            f_out.close()

            # ファイル名連番のインデックスを繰り上げる
            i += 1

このスクリプトを実行すると、見事全フレームがJPEGファイルとして書き出されました。ここまで書いたところで、冒頭の元も子もない話に続きます。あぁ徒労徒労。

フリーソフトで、AIを使ったアップコンバート

こうして取り出した映像のサイズは640x480のSD画質、ドットがジャギジャギ、だいぶ見辛いものでした。

そこで、ニューラルネットワークで画像の解像度を上げる、Waifu2xというアプリを使ってみることにしました。

AI系のOSSを使うときは、大抵環境構築が面倒ですが、Windows用にWaifu-caffeというGUIツールが公開されていて、これを使うと面倒なところをすっ飛ばして、すぐに使うことができます。

www.gigafree.net

拡大倍率を設定したら、あとはボタンを押すだけです。

CPUで処理することもできますが、恐ろしく時間がかかるので、動画に使うにはCUDA対応のGPU必須です。

フリーソフトでAIを使ったフレーム補完

苦労して取り出した動画は、フレームレートも低めだったので、つぎはフレーム補完です。

こちらは「Frowframe」というGUIアプリを使うと超簡単です、補完倍率を×2〜16の範囲で選んで、ボタンを押すだけです。(これもCUDAを使わないとけっこう厳しい)

www.gigafree.net

まとめ

  • 謎形式の動画を手に入れたら、まずはFFmpegを通してみる。

南無