【その2】ZOOM, Teamsなどのためのサブタイトル(字幕)表示ツール【受信・表示プログラム】


【その2】ZOOM, Teamsなどのためのサブタイトル(字幕)表示ツール【受信・表示部】

受信・表示プログラム

 前回 https://qiita.com/quittardis/items/317df7b23a64e82bf6a2 
 の続きです。
 前回の送信プログラムでudp経由で送られてきた全角漢字をカメラ画像にスーパー
インポーズして字幕として表示します。さらにこの画像をSpoutで仮想カメラ化して
ZOOMやTeamsで使えるようにします。

ソースコードのbugfix版はhttps://github.com/ultrahamlet/SjFX のsrcフォルダに置きました。

(buildが苦手という方は、このhttps://github.com/ultrahamlet/SjFX
gitにあるbinaryファイルで実験できる。
SjFX.exeが受信・表示プログラム。WindowsProject.exeが文字送信プログラム。
実験時にWebCamの接続とSpoutCamのインストールも忘れずに)
 
 先ず、SpoutSDK https://spout.zeal.co/
をopenframeworksのプロジェクトフォルダと同じ階層に置きます。

openframeworksのアドオンは、

ofxNetworks
ofxXmlSettings

を追加します。

ofApp.hでinlcludeに以下の四行を追加します。

#include "ofxXmlSettings.h"
#include "..\..\SpoutSDK\SpoutSender.h"
#include <Windows.h>
#include "ofxNetwork.h"

ofApp.h

ofApp.hでinlcludeに以下のように変数を追加します。

        ofVideoGrabber grabber;
        //
        char sendername[256];     // Sender name
        SpoutSender sender;    // Spout sender object
        unsigned int senderwidth;  // Dimensions of the sender can be independent
        unsigned int senderheight; // of the application window if using an fbo
        ofFbo  oFbo;
        ofFbo spFbo;           // For texture send example
        // udp FONT
        ofxUDPManager udpConnectionRx;
        ofxUDPManager udpConnectionTx;

        string rxMessage;
        string txMessage;
        string recvStr;
        string ostr;
        BOOL received;
        ofTrueTypeFont font;

ofApp.cppの#include "ofApp.h"以下の行を追加します。
主に漢字コードを変換する関数です。

#include <codecvt>
//--------------------------------------------------------------
std::wstring multi_to_wide_capi(std::string const& src)
{
    std::size_t converted{};
    std::vector<wchar_t> dest(src.size(), L'\0');
    if (::_mbstowcs_s_l(&converted, dest.data(), dest.size(), src.data(), _TRUNCATE, ::_create_locale(LC_ALL, "jpn")) != 0) {
        throw std::system_error{ errno, std::system_category() };
    }
    dest.resize(std::char_traits<wchar_t>::length(dest.data()));
    dest.shrink_to_fit();
    return std::wstring(dest.begin(), dest.end());
}
std::string wide_to_utf8_cppapi(std::wstring const& src)
{
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    return converter.to_bytes(src);
}

std::string multi_to_utf8_cppapi(std::string const& src)
{
    auto const wide = multi_to_wide_capi(src);
    return wide_to_utf8_cppapi(wide);
}

std::string toUtf8(const std::wstring &str)
{
    std::string ret;
    int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0, NULL, NULL);
    if (len > 0)
    {
        ret.resize(len);
        WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.length(), &ret[0], len, NULL, NULL);
    }
    return ret;
}

ofApp::setup()

void ofApp::setup()に以下の行を追加します。
フォントの読み込みと、
udpの接続の設定です。
フォントはdataフォルダの下のFotnsにWindows/Fontsからコピーしておきます。

grabber.setup(ofGetWidth(), ofGetHeight());

    senderwidth = ofGetWidth();
    senderheight = ofGetHeight();
    // Create an RGBA fbo for texture transfers
    spFbo.allocate(senderwidth, senderheight, GL_RGBA);
    oFbo.allocate(ofGetWidth(), ofGetHeight(), GL_RGBA);
    //oFbo.getTextureReference().getTextureData().bFlipTexture = true;

    // If no name is specified, the executable name is used.
    sender.SetSenderName(sendername);
    // Update caption in case of multiples of the same sender
    ofSetWindowTitle(sender.GetName());
    //
    // Font setting
    ofTrueTypeFontSettings fsettings("Fonts/meiryo.ttc", 24);
    fsettings.addRanges(ofAlphabet::Emoji);//絵文字
    fsettings.addRanges(ofAlphabet::Japanese);//日本語
    fsettings.addRange(ofUnicode::Space);//スペース
    fsettings.addRange(ofUnicode::IdeographicSpace);//全角スペース
    fsettings.addRange(ofUnicode::Latin);//アルファベット等
    fsettings.addRange(ofUnicode::Latin1Supplement);//記号、アクサン付き文字など
    fsettings.addRange(ofUnicode::NumberForms);//数字?
    fsettings.addRange(ofUnicode::Arrows);//矢印
    fsettings.addRange(ofUnicode::MathOperators);//数式記号
    fsettings.addRange(ofUnicode::Hiragana);//ひらがな
    fsettings.addRange(ofUnicode::Katakana);//カタカナ
    fsettings.addRange(ofUnicode::MiscSymbolsAndPictographs);//絵文字など
    fsettings.addRange(ofUnicode::Emoticons);//エモーティコン
    //settings.addRange(ofUnicode::KatakanaHalfAndFullwidthForms);//エモーティコン
    //
    if (!font.load(fsettings))
        cout << "couldn't load font" << endl;
    //
    // udp connect
    udpConnectionRx.Create();
    udpConnectionRx.Bind(12345); //incomming data on my port # ...  
    udpConnectionRx.SetNonBlocking(true);

    received = false;

ofApp::update()

void ofApp::update()を以下のリストを追加します。
udpデータを待ち受け受信します。
受信したデータは、recvStrにストアします。


grabber.update();

    // UDP 受信
    char data[512];
    //unsigned short int *val;
    udpConnectionRx.Receive(data, 512);
    //std::cout << str << "-" <<  std::endl;
    uint16_t *val = (uint16_t*)data;
    //std::cout << val[0] << std::endl;
    BOOL strOK = true;
    for (int i = 0; i < sizeof(val); i++) {
        if (val[i] < 256) { strOK = false; break; }
    }
    if (strOK) {
        recvStr = data;
        received = true;
        std::cout << recvStr << std::endl;
        // shift-jis -> utf8
        ostr = multi_to_utf8_cppapi(recvStr);
        std::cout <<  "Received" << std::endl;
    }

ofApp::draw()

void ofApp::draw()に以下のリストを追加します。

受信したデータを表示し、Spoutで仮想カメラに送信します。
ソースコードのbugfix版はhttps://github.com/ultrahamlet/SjFX のsrcフォルダに置きました。以下のコードは、2月16日以降修正しています。それ以前のコードでは、SpoutCamに文字が出力されません。

    oFbo.begin();

     ofSetColor(255, 255, 255);

     grabber.draw(0, 0);
    // font.drawString(u8"漢字テスト", 0, 200);
     if (received) font.drawString(ostr, 200, ofGetHeight()-30);
    oFbo.end();

    spFbo.begin();    
    //grabber.draw(0, 0);
    if (flipY) {
        ofScale(-1, 1);
        ofTranslate(-ofGetWidth(), 0);
    }
    oFbo.draw(0, 0);
     sender.SendFbo(oFbo.getId(), senderwidth, senderheight, false);
    spFbo.end();

    oFbo.draw(0, 0);

SpoutCamのインストール

最後にSpoutCam-2.023をインストールします。
 SpoutCam-2.023\release\x64下の
 _register_run_as_admin.bat
 (zoom用に32bit版もインストールする。)
を、管理者として実行します。
これで、ZOOM、TeamsなどからカメラとしてSpoutを選択します。

あっ忘れてました。

 dataフォルダ化に以下の内容のsttings.htmlを置いてください。
ここにはカメラに最適の縦横の値を書いておきます。

<settings>
    <app>
        <width>960</width>
        <height>544</height>
    </app>
</settings>

 
gitのbinの中のMySetting.exeでも設定できる。