[C++] 186 FLTK : SFTP補助アプリ SMBの一部導入

[M1 Mac, Big Sur 11.6.8, clang 13.0.0, FLTK 1.3.8, NO IDE]

MacとWindows11間のファイル移動に使用していたOpenSSHサーバが突然使えなくなり、復旧もできないのでSMBに変更しました。

mount_smbfsファイルはsbinディレクトリにあり、.bash_profileなどでパスを通しておく必要があります。

Mac-Mac間、Mac-Linux間はこれまで通りSFTPを使います。

OpenSSHサーバについてはWindows11関連のネット情報がほぼ皆無で本当に使えるのかどうか疑問ではあります。

時たまイジるWindows11は本当に使いにくく、Windows Vista、Windows8以来の失敗作という評価が私の中で固まりつつあります。Windows3.1以降では最悪だと思います。大変でしょうが、次世代OSの開発を急いでもらいたいものです。

extern char *dirName;

void conn_cb(Fl_Widget*, void*) {
    string cmd_conn;
    string pc;

    choice_num = choice -> value();
    switch(choice_num){
        case 0:{
            pc = "xxx.local"; // Mac mini Intel
            break;
        }
        case 1:{
            pc = "xxx.local"; // MacBook Air M1
            break;
        }
        case 2:{
            pc = "xxx.local"; // MacBook Intel
            break;
        }
        case 3:{
            pc = "mount_smbfs //[ユーザ名]@192.168.xx.x/share /Users/[ユーザ名]/share"; // WindowsPC
            break;
        }
        case 4:{
            pc = "xxx.local"; // LinuxPC
            break;
        }
    }

    if (choice_num != 3){
        cmd_conn = "sftp " + pc;
    } else {
        cmd_conn = pc;
    }
    cout << "cmd_conn " << cmd_conn << endl;

    conn_input -> value("");
    conn_input -> value(cmd_conn.c_str());

    string cmdConnCopy = "echo '" + cmd_conn + "' | LANG=ja_JP.UTF-8 pbcopy";
    output_line -> insert(cmdConnCopy.c_str());
    output_line -> insert("\n");
    system(cmdConnCopy.c_str());

}

void cmd_cb(Fl_Widget*, void*) {
    string cmd0;
    string cmd1;
    string cmd;

    int onoff_put = put_rbtn->value();
    int onoff_dir = dir_rbtn->value();

    if (choice_num != 3){
        if (onoff_put == 1){
            cmd0 = "put";
        } else {
            cmd0 = "get";
        }
    } else {
        if (onoff_put == 1){
            cmd0 = "cp";
        } else {
            cmd0 = "cp";
        }
    }

    if (onoff_dir == 1){
        cmd1 = "-r";
    } else {
        cmd1 = "";
    }

    const char* fileName = file_input -> value();
    const char* toName = to_input -> value();

    if (choice_num != 3){
        cmd = cmd0 + " " + cmd1 + " \"" + string(fileName) + "\" " + string(toName);
    } else {
        if (onoff_dir == 1){
            cmd = cmd0 + " " + cmd1 + " \"" + string(fileName) + "\" /Users/[ユーザ名]/share/" + dirName;
        } else {
            cmd = cmd0 + " " + cmd1 + " \"" + string(fileName) + "\" /Users/[ユーザ名]/share";
        }
    }
    cout << "cmd " << cmd << endl;

    cmd_input -> value("");
    cmd_input -> value(cmd.c_str());

    string cmdCopy = "echo '" + cmd + "' | LANG=ja_JP.UTF-8 pbcopy";
    output_line -> insert(cmdCopy.c_str());
    output_line -> insert("\n");
    system(cmdCopy.c_str());

}

[C++ & Python] 185 FLTK : LLDB補助アプリの製作着手

[M1 Mac, Big Sur 11.6.8, clang 13.0.0, Python 3.10.4, NO IDE]

早いもので前作のビデオツールアプリ完成から20日ほど経過していました。

LLDBから得られたレジスタやメモリのデータをExcelにまとめるツールを作ることにしました。逆アセンブリコード1行ごとのレジスタ値、スタック領域メモリ値を一気にまとめます。

C++とPythonで作成します。役割分担は以下の通りです。

C++ : GUI(FLTK)、LLDBコマンド作成・実行・ログ取得
Python : LLDBログから各データを抽出しExcelファイルにまとめる

まずはPythonから取り組みます。

LLDBログデータ例

[C++] 184 C++ & アセンブラ用Makefile

[M1 Mac, Big Sur 11.6.8, clang 13.0.0, NO IDE]

簡単なコードをアセンブリ言語で書くためのMakefileを作成しました。

cppファイルからsファイルに変換して叩き台にすることもできますし、sファイルを一から書くことも可能です。

きょうびアセンブリ言語を使うのは命令セットの探索やインラインアセンブラなど一部の用途を除いて酔狂でしかないでしょう。

# コンパイラ設定
COMPILER = clang++
DEBUG = -g

# オプション設定
CPPFLAGS = -std=c++17

# includeパス(-I)
INCLUDE = -I./include -I/Volumes/DATA_m1/code/cpp/mylib/include

# ソースファイル
SRCDIR = ./src
SRCS = $(shell find $(SRCDIR) -type f)

# アセンブリファイル
ASMDIR = ./asm
ASMS = $(addprefix $(ASMDIR), $(patsubst ./src/%.cpp,/%.s,$(SRCS)))

# オブジェクトファイル
OBJDIR = ./obj
OBJS = $(addprefix $(OBJDIR), $(patsubst ./src/%.cpp,/%.o,$(SRCS)))

# 実行ファイル
TARGETDIR = ./bin
TARGET = test

# $<:元ファイル $@:作成ファイル

# cppファイルからsファイル作成
$(ASMDIR)/%.s: $(SRCDIR)/%.cpp
	$(COMPILER) $(CPPFLAGS) $(INCLUDE) $(DEBUG) -fno-pic -fomit-frame-pointer -S $<
	mv *.s $(ASMDIR)

# sファイルからoファイル作成
$(OBJDIR)/%.o: $(ASMDIR)/%.s
	$(COMPILER) -o $@ $< -c

# oファイルから実行ファイル作成
$(TARGET):$(OBJS)
	$(COMPILER) -o $(TARGETDIR)/$@ $(OBJS)

# ビルド(実行ファイル作成)
.PHONY:tar
tar: $(TARGET)

# cppファイルからsファイル作成
.PHONY:asm
asm: $(ASMS)

# sファイルからoファイル作成
.PHONY:obj
obj: $(OBJS)

# oファイル・実行ファイル削除
.PHONY:clean
clean:
	rm -rf $(OBJS) $(TARGETDIR)/$(TARGET)

[C++] 183 FLTK : 動画を結合する FFmpeg

[M1 Mac, Big Sur 11.6.8, clang 13.0.0, FLTK 1.3.8, NO IDE]

ビデオツールアプリに動画を結合する機能を実装しました。

これで簡単な編集であればこのアプリで済ませることができるようになりました。

アプリ搭載機能
1.動画からサイズ、時間、フレームレートなどメタ情報を取得する
2.動画を各フレームに切り出す(静止画としても利用可)
3.指定したフレームから動画を作成する
4.動画にぼかしを入れる(FFmpegライブラリやハードが許す限り何ヶ所でも)
5.動画を結合する

string listFile = "list.txt";
string concatFile = "concat.txt";

void concatCB(Fl_Widget*, void*){
    // LIST欄の文字列をテキストファイル化
    const char* list = list_input -> value();
    cout << "list "  << list << endl;

    std::ofstream file;
    file.open(listFile, std::ios::out);
    file << string(list) << endl;
    file.close();

    const char* output = out3_input -> value();
    string cmd = "/opt/homebrew/Cellar/ffmpeg/5.1/bin/ffmpeg -f concat -safe 0 -i " + listFile + " -c copy " + string(output) +  " 2>" + concatFile;
    cmdBuffer2 -> append(cmd.c_str());
    cmdBuffer2 -> append("\n");
    cout << "cmd: "<< cmd << endl;

    // cmdTextDisplay2にcmdを表示する
    cmdTextDisplay2->buffer(cmdBuffer2);

    // コマンド実行
    system(cmd.c_str());

    // browser(STDOUT)にコマンドのログを表示する
    browser2 -> load(concatFile.c_str());
    int line_num = browser2->size();
    browser2 -> bottomline(line_num);
}

[C++] 182 FLTK : 動画の一部を複数ぼかす FFmpeg

[M1 Mac, Big Sur 11.6.8, clang 13.0.0, FLTK 1.3.8, NO IDE]

前回作成したコードを導入し、動画の一部を複数ぼかすことができるようにしました。

動画では3ヶ所にモザイクをかけています。

string filterCmdMake(string input,string output,string filters)
{   
    vector<string> crops;
    vector<string> overs;
    string comp;

    vector<string> list_filter = spt2.splits(filters,",");
    int num = list_filter.size();
    
    for (int i=0;i < num;i++){
        string crop = "[0:v]crop=" + list_filter[i] + ",boxblur=4[b" + to_string(i) + "]";
        crops.push_back(crop);
    }

    for (string ele:crops){
        cout << ele << endl;
    }

    for (int i=0;i < num;i++){
        vector<string> values = spt2.splits(list_filter[i],":");
        if (i==0){
            string over = "[0:v][b0]overlay=" + values[2] + ":" + values[3] + "[ovr0]";
            overs.push_back(over);
        } else {
            string over = "[ovr" + to_string(i-1) + "][b" + to_string(i) + "]overlay=" + values[2] + ":" + values[3] + "[ovr" + to_string(i) + "]";
            overs.push_back(over);
        }
    }

    for (string ele:overs){
        cout << ele << endl;
    }

    crops.insert(crops.end(), overs.begin(), overs.end());

    int num2 = crops.size();
    for (int i = 0;i < num2;i++){
        if (i != num2 - 1){
            comp += crops[i] + ";\\" + "\n";
        } else {
            comp += crops[i];
        }
    }

    cout << "comp: " << comp << endl;

    string cmd =  "/opt/homebrew/Cellar/ffmpeg/5.1/bin/ffmpeg -i " + input + " -filter_complex \\\n\"" + comp + "\"\\\n -map \"[ovr" + to_string(num-1) + "]\" " + output;
    cout << "cmd: " << cmd << endl;

    return cmd;
}

[C++] 181 FFmpegコマンド作成 : 動画に複数のぼかしを入れる

[M1 Mac, Big Sur 11.6.8, clang 13.0.0]

動画に複数のぼかしを入れるFFmpegコマンド作成プログラムを書きました。

これで四角形のモザイクを何ヶ所でも入れることができます。

#include <cppstd.h>
#include <Split.h> // 自製文字列分割クラス

class Split spt; 

int main()
{   
    vector<string> crops;
    vector<string> overs;
    string comp;
    string input = "input.mp4";
    string output = "output.mp4";
    string filters = "227:168:411:117,319:177:650:117,416:80:121:657";

    vector<string> list_filter = spt.splits(filters,",");
    int num = list_filter.size();
    
    for (int i=0;i < num;i++){
        string crop = "[0:v]crop=" + list_filter[i] + ",boxblur=4[b" + to_string(i) + "]";
        crops.push_back(crop);
    }

    for (string ele:crops){
        cout << ele << endl;
    }

    for (int i=0;i < num;i++){
        vector<string> values = spt.splits(list_filter[i],":");
        if (i==0){
            string over = "[0:v][b0]overlay=" + values[2] + ":" + values[3] + "[ovr0]";
            overs.push_back(over);
        } else {
            string over = "[ovr" + to_string(i-1) + "][b" + to_string(i) + "]overlay=" + values[2] + ":" + values[3] + "[ovr" + to_string(i) + "]";
            overs.push_back(over);
        }
    }

    for (string ele:overs){
        cout << ele << endl;
    }

    crops.insert(crops.end(), overs.begin(), overs.end());

   int num2 = crops.size();
    for (int i = 0;i < num2;i++){
        if (i != num2 - 1){
            comp += crops[i] + ";\\" + "\n";
        } else {
            comp += crops[i];
        }
    }

    cout << "comp: " << comp << endl;

    string cmd =  "ffmpeg -i " + input + " -filter_complex \\\n\"" + comp + "\"\\\n -map \"[ovr" + to_string(num-1) + "]\" " + output;

    cout << "cmd: " << cmd << endl;
}
--------------------------------------------------
作成されたコマンド
--------------------------------------------------
ffmpeg -i input.mp4 -filter_complex \
"[0:v]crop=227:168:411:117,boxblur=4[b0];\
[0:v]crop=319:177:650:117,boxblur=4[b1];\
[0:v]crop=416:80:121:657,boxblur=4[b2];\
[0:v][b0]overlay=411:117[ovr0];\
[ovr0][b1]overlay=650:117[ovr1];\
[ovr1][b2]overlay=121:657[ovr2]"\
 -map "[ovr2]" output.mp4

[FFmpeg] 動画に複数のぼかしを入れる

[M1 Mac, Big Sur 11.6.8]

FFmpegのコマンドがとにかくわかりにくいので、書き留めておきます。

開発中のビデオツールアプリに実装するには、このコマンドをC++で生成する必要があります。

FFmpeg関連の情報はネットに数多くありますが、どういったユーザー層なのか気になります。C/C++ユーザーよりもコマンドライン使いが多そうです。

ffmpeg -i out.mp4 -filter_complex \          --- (1)
 "[0:v]crop=265:154:648:103,boxblur=4[b0]; \ --- (2)
  [0:v]crop=94:111:572:267,boxblur=4[b1]; \  --- (3)
  [0:v][b0]overlay=648:103[ovr0]; \          --- (4)
  [ovr0][b1]overlay=572:267[ovr1]" \         --- (5)
-map "[ovr1]" out2.mp4                       --- (6)

(1) 入力ファイルはout.mp4。以下、-filter_complexを記す。
(2) 入力ファイル0番目の映像[0:v]について、x:648,y:103の位置からw:265,h:154のサイズでクロップし、レベル4のboxblur処理をする。これをb0とする。
(3) 入力ファイル0番目の映像について、x:572,y:267の位置からw:94,h:111のサイズでクロップし、レベル4のboxblur処理をする。これをb1とする。
(4) 入力ファイル0番目の映像とb0をx:648,y:103の位置で重ねる。これをovr0とする。
(5) ovr0とb1をx:572,y:267の位置で重ねる。これをovr1とする。
(6) ovr1をマッピングし、out2.mp4として出力する。

[C++] 180 FLTK : 動画の一部をぼかす FFmpeg

[M1 Mac, Big Sur 11.6.8, clang 13.0.0, FLTK 1.3.8, NO IDE]

動画の一部(四角形領域)をぼかす機能を実装しました。

今のところ1ヶ所のみですが、複数の領域にモザイクをかけられるようにします。

// 計算ボタンのコールバック関数 変数x,yはmathライブラリで使われているためxx,yyを使用
void calcCB(Fl_Widget*, void*) {
    xa = (int)(xx1 * ((float)widthSub1/480));
    xb = (int)(xx2 * ((float)widthSub1/480));
    ya = (int)(yy1 * ((float)heightSub1/360));
    yb = (int)(yy2 * ((float)heightSub1/360));

    cout << "widthSub1 " << widthSub1 << " heightSub1 " << heightSub1 << endl;
    cout << "xx1 " << xx1 << " xx2 " << xx2 << " yy1 " << yy1 << " yy2 " << yy2 << endl;
    cout << "xa " << xa << " xb " << xb << " ya " << ya << " yb " << yb << endl;

    wa = xb - xa;
    ha = yb - ya;

    filter = to_string(wa) + ":" + to_string(ha) + ":" + to_string(xa) + ":" + to_string(ya);
    filter2 = to_string(xa) + ":" + to_string(ya);

    fil_input -> value(filter.c_str());
}
// フィルタボタンのコールバック関数
void filCB(Fl_Widget*, void*){
    const char* output = outputLine2 -> value();
    const char* output2 = out2_input -> value();

    string filtercmd = "ffmpeg -i " + string(output) + " -filter_complex \"[0:v]crop=" + filter + ",boxblur=4[fg];[0:v][fg]overlay=" + filter2 + "[v]\" -map \"[v]\" " + string(output2) + " 2> " + filterFile;

    // CMD追加
    cmdBuffer2 -> append(filtercmd.c_str());
    cmdBuffer2 -> append("\n");
    cout << "filtercmd: "<< filtercmd << endl;

    // cmdTextDisplay2にcmdを表示する
    cmdTextDisplay2->buffer(cmdBuffer2);

    // コマンド実行
    system(filtercmd.c_str());

    // browserにfilterFileの内容を表示する
    browser2 -> load(filterFile.c_str());
    int line_num = browser2->size();
    browser2 -> bottomline(line_num);

}

[C++] 179 FLTK : Fl_Box内の相対座標をマウスクリックで取得する Fl::event_x()

[M1 Mac, Big Sur 11.6.8, clang 13.0.0, FLTK 1.3.8, NO IDE]

動画の一部をマスクする長方形の座標と大きさを把握するため、マウスをクリックしてx座標、y座標を取得できるようにしました。

マウス左ボタンを押すとx1とy1、離すとx2とy2を取得します。マウスをドラッグしている間は長方形を描画させたかったのですが、うまくできませんでした。このデータを元にマスク用の画像を作成し、重ねた状態で動画を合成する予定です。

#pragma once
#include <FLstd.h>
#include "cppstd.h"

class BoxXY : public Fl_Box {
    Fl_Input* input_line1;
    Fl_Input* input_line2;
    Fl_Input* input_line3;
    Fl_Input* input_line4;

    public:
        BoxXY(int x, int y, int width_input, int height_input, Fl_Input* input1,Fl_Input* input2, Fl_Input* input3,Fl_Input* input4);
    private:
        int handle(int);
};
#include "BoxXY.h"

BoxXY::BoxXY(int x, int y, int width_input, int height_input, Fl_Input* input1,Fl_Input* input2, Fl_Input* input3,Fl_Input* input4) : Fl_Box(FL_NO_BOX, x, y, width_input, height_input, "") 
{
    this->input_line1 = input1;
    this->input_line2 = input2;
    this->input_line3 = input3;
    this->input_line4 = input4;
}

int BoxXY::handle(int event){
    switch (event) {
        case FL_PUSH:{ // Box左上の座標は(65,190)
            int x1 = Fl::event_x() - 65;
            int y1 = Fl::event_y() - 190;

            input_line1->value(to_string(x1).c_str());
            input_line1->textsize(12);

            input_line2->value(to_string(y1).c_str());
            input_line2->textsize(12);

            return 1;
        }
        case FL_RELEASE:{
            int x2 = Fl::event_x() - 65;
            int y2 = Fl::event_y() - 190;

            input_line3->value(to_string(x2).c_str());
            input_line3->textsize(12);

            input_line4->value(to_string(y2).c_str());
            input_line4->textsize(12);

            return 1;
        }
        default:
            return Fl_Box::handle(event);
    }
}

[C++] 178 FLTK : 動画からフレームレートを取得 FFmpeg

[M1 Mac, Big Sur 11.6.8, clang 13.0.0, FLTK 1.3.8, NO IDE]

開発中のビデオツールアプリにおいて、すでに分割したフレーム群から動画を作成できるようにしました。

さらに動画の一部をマスクする機能を実装して、このアプリはとりあえず完成としたいです。

// 解析ボタンのコールバック関数
void analyzeCB(Fl_Widget*, void*) {
    string bufferStr2;
    std::ifstream file;
    string fpsFile = "fps.txt";
    string buffer;

    fpsInput2 -> value("\0");
    // 対象ファイルパス取得
    const char* path = inputLine2->value();
    
    // path未入力の場合は既存の静止画群のFPSを取得し表示
    if (string(path) == ""){
        cout << "pathなし" << endl;

        // fps.txtからfps(分数)を取得
        file.open(fpsFile, std::ios::in);
        std::getline(file, buffer);
        string fps_str = buffer;

        vector<string> list_fps = spt2.splits(fps_str,"/");
        string top0 = list_fps[0];
        float top = stof(top0);
        string bottom0 = list_fps[1];
        float bottom = stof(bottom0);

        fps = top/bottom;
        cout << "fps "<< fps << endl;

        fpsInput2 -> value((to_string(fps)).c_str());
        fpsInput2 -> position(0);
        
        outputLine2 -> value("out.mp4");

        toImagesRbtn -> value(false);
        toVideoRbtn -> value(true);

        return;
    }

    cout << "path "<< path << endl;

    string path_str = string(path);
    bufferStr2 += "path_str: " + path_str + "\n";

    // path内半角スペースをアンダースコアへ置き換え
    path2 = underScoreReplace(string(path_str));
    bufferStr2 += "path2: " + path2 + "\n";

    // 元ファイルをリネーム
    rename(path, path2.c_str());

    // 出力ファイル名を作成
    string outputFile0 = spt2.splitJoin(path2, ".", 0, -2);
    outputFile0.pop_back();
    outputFile = outputFile0 + "_trimmed.mp4";
    cout << "outputFile " << outputFile << endl;

    outputLine2 -> value(outputFile.c_str());

    // フレームレート出力コマンドcmd作成
    string cmd = "/opt/homebrew/Cellar/ffmpeg/5.1/bin/ffprobe -v error -select_streams v -show_entries stream=avg_frame_rate -of csv=p=0 " + path2;
    // fps.txtとしても出力
    string cmd2 = "/opt/homebrew/Cellar/ffmpeg/5.1/bin/ffprobe -v error -select_streams v -show_entries stream=avg_frame_rate -of csv=p=0 " + path2 + " 1> " + fpsFile;

    cout << "cmd: "<< cmd << endl;

    cmdBuffer2 -> append(cmd.c_str());
    cmdBuffer2 -> append("\n");

    bufferStr2 += cmd + "\n";

    // cmdTextDisplay2にcmdを表示する
    cmdTextDisplay2->buffer(cmdBuffer2);

    // FPSを取得し表示
    showFPS(cmd);
    system(cmd2.c_str());

    textBuffer2 -> append(bufferStr2.c_str());
    textDisplay2 -> buffer(textBuffer2);
}